Compare commits
12 Commits
jazz-run@0
...
jazz-auth-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55cb83e6e0 | ||
|
|
6290088fec | ||
|
|
b9c17b37db | ||
|
|
6c76ff8fbf | ||
|
|
3c6a2a6092 | ||
|
|
e8a950e61a | ||
|
|
e2cbf035de | ||
|
|
47599b6307 | ||
|
|
901d0762ee | ||
|
|
d1c1b0c5cc | ||
|
|
cf4ad7285d | ||
|
|
2983c7bd58 |
@@ -1,5 +1,20 @@
|
||||
# passkey-svelte
|
||||
|
||||
## 0.0.102
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c76ff8]
|
||||
- jazz-tools@0.15.13
|
||||
|
||||
## 0.0.101
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1c1b0c]
|
||||
- Updated dependencies [cf4ad72]
|
||||
- jazz-tools@0.15.12
|
||||
|
||||
## 0.0.100
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chat-svelte",
|
||||
"version": "0.0.100",
|
||||
"version": "0.0.102",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
3
examples/server-side-validation/vercel.json
Normal file
3
examples/server-side-validation/vercel.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"ignoreCommand": "echo true"
|
||||
}
|
||||
@@ -1,5 +1,17 @@
|
||||
# cojson-storage-indexeddb
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- cojson@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- cojson@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cojson-storage-indexeddb",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# cojson-storage-sqlite
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- cojson@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- cojson@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cojson-storage-sqlite",
|
||||
"type": "module",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# cojson-transport-nodejs-ws
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- cojson@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- cojson@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cojson-transport-ws",
|
||||
"type": "module",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# cojson
|
||||
|
||||
## 0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
## 0.15.10
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"devDependencies": {
|
||||
"@opentelemetry/sdk-metrics": "^2.0.0",
|
||||
"libsql": "^0.5.13",
|
||||
|
||||
@@ -82,6 +82,11 @@ export class LocalNode {
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
removeStorage() {
|
||||
this.storage?.close();
|
||||
this.storage = undefined;
|
||||
}
|
||||
|
||||
getCoValue(id: RawCoID) {
|
||||
let entry = this.coValues.get(id);
|
||||
|
||||
@@ -348,12 +353,10 @@ export class LocalNode {
|
||||
skipLoadingFromPeer?: PeerID,
|
||||
skipRetry?: boolean,
|
||||
): Promise<CoValueCore> {
|
||||
if (!id) {
|
||||
throw new Error("Trying to load CoValue with undefined id");
|
||||
}
|
||||
|
||||
if (!id.startsWith("co_z")) {
|
||||
throw new Error(`Trying to load CoValue with invalid id ${id}`);
|
||||
if (typeof id !== "string" || !id.startsWith("co_z")) {
|
||||
throw new TypeError(
|
||||
`Trying to load CoValue with invalid id ${Array.isArray(id) ? JSON.stringify(id) : id}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (this.crashed) {
|
||||
|
||||
@@ -54,6 +54,38 @@ describe("loading coValues from server", () => {
|
||||
`);
|
||||
});
|
||||
|
||||
test("coValue load throws on invalid id", async () => {
|
||||
const { node } = setupTestNode({
|
||||
connected: true,
|
||||
});
|
||||
|
||||
expect(async () => await node.load("test" as any)).rejects.toThrow(
|
||||
"Trying to load CoValue with invalid id test",
|
||||
);
|
||||
expect(async () => await node.load(null as any)).rejects.toThrow(
|
||||
"Trying to load CoValue with invalid id null",
|
||||
);
|
||||
expect(async () => await node.load(undefined as any)).rejects.toThrow(
|
||||
"Trying to load CoValue with invalid id undefined",
|
||||
);
|
||||
expect(async () => await node.load(1 as any)).rejects.toThrow(
|
||||
"Trying to load CoValue with invalid id 1",
|
||||
);
|
||||
expect(async () => await node.load({} as any)).rejects.toThrow(
|
||||
"Trying to load CoValue with invalid id [object Object]",
|
||||
);
|
||||
expect(async () => await node.load([] as any)).rejects.toThrow(
|
||||
"Trying to load CoValue with invalid id []",
|
||||
);
|
||||
expect(async () => await node.load(["test"] as any)).rejects.toThrow(
|
||||
'Trying to load CoValue with invalid id ["test"]',
|
||||
);
|
||||
expect(async () => await node.load((() => {}) as any)).rejects.toThrow(
|
||||
"Trying to load CoValue with invalid id () => {\n }",
|
||||
);
|
||||
expect(async () => await node.load(new Date() as any)).rejects.toThrow();
|
||||
});
|
||||
|
||||
test("unavailable coValue retry with skipRetry set to true", async () => {
|
||||
const client = setupTestNode();
|
||||
const client2 = setupTestNode();
|
||||
|
||||
@@ -991,7 +991,7 @@ describe("LocalNode.load", () => {
|
||||
|
||||
// @ts-expect-error Testing with undefined ID
|
||||
await expect(client.node.load(undefined)).rejects.toThrow(
|
||||
"Trying to load CoValue with undefined id",
|
||||
"Trying to load CoValue with invalid id undefined",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# jazz-auth-betterauth
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c76ff8]
|
||||
- jazz-tools@0.15.13
|
||||
- jazz-betterauth-client-plugin@0.15.13
|
||||
- cojson@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1c1b0c]
|
||||
- Updated dependencies [cf4ad72]
|
||||
- jazz-tools@0.15.12
|
||||
- jazz-betterauth-client-plugin@0.15.12
|
||||
- cojson@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jazz-auth-betterauth",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# jazz-betterauth-client-plugin
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-betterauth-server-plugin@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-betterauth-server-plugin@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jazz-betterauth-client-plugin",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# jazz-betterauth-server-plugin
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c76ff8]
|
||||
- jazz-tools@0.15.13
|
||||
- cojson@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1c1b0c]
|
||||
- Updated dependencies [cf4ad72]
|
||||
- jazz-tools@0.15.12
|
||||
- cojson@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jazz-betterauth-server-plugin",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# jazz-react-auth-betterauth
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c76ff8]
|
||||
- jazz-tools@0.15.13
|
||||
- jazz-auth-betterauth@0.15.13
|
||||
- jazz-betterauth-client-plugin@0.15.13
|
||||
- cojson@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1c1b0c]
|
||||
- Updated dependencies [cf4ad72]
|
||||
- jazz-tools@0.15.12
|
||||
- jazz-auth-betterauth@0.15.12
|
||||
- jazz-betterauth-client-plugin@0.15.12
|
||||
- cojson@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jazz-react-auth-betterauth",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.tsx",
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# jazz-run
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c76ff8]
|
||||
- jazz-tools@0.15.13
|
||||
- cojson@0.15.13
|
||||
- cojson-storage-sqlite@0.15.13
|
||||
- cojson-transport-ws@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1c1b0c]
|
||||
- Updated dependencies [cf4ad72]
|
||||
- jazz-tools@0.15.12
|
||||
- cojson@0.15.12
|
||||
- cojson-storage-sqlite@0.15.12
|
||||
- cojson-transport-ws@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"bin": "./dist/index.js",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"exports": {
|
||||
"./startSyncServer": {
|
||||
"import": "./dist/startSyncServer.js",
|
||||
@@ -28,11 +28,11 @@
|
||||
"@effect/printer-ansi": "^0.34.5",
|
||||
"@effect/schema": "^0.71.1",
|
||||
"@effect/typeclass": "^0.25.5",
|
||||
"cojson": "workspace:0.15.11",
|
||||
"cojson-storage-sqlite": "workspace:0.15.11",
|
||||
"cojson-transport-ws": "workspace:0.15.11",
|
||||
"cojson": "workspace:0.15.13",
|
||||
"cojson-storage-sqlite": "workspace:0.15.13",
|
||||
"cojson-transport-ws": "workspace:0.15.13",
|
||||
"effect": "^3.6.5",
|
||||
"jazz-tools": "workspace:0.15.11",
|
||||
"jazz-tools": "workspace:0.15.13",
|
||||
"ws": "^8.14.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# jazz-tools
|
||||
|
||||
## 0.15.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6c76ff8: Fix load failures when loading a missing ref declared with z.optional and Schema.optional
|
||||
- cojson@0.15.13
|
||||
- cojson-storage-indexeddb@0.15.13
|
||||
- cojson-transport-ws@0.15.13
|
||||
|
||||
## 0.15.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d1c1b0c: Fix stuck authentication when using onAnonymousAccountDiscarded with a storage
|
||||
- cf4ad72: fix unhandled rejection on CoValue.load
|
||||
- cojson@0.15.12
|
||||
- cojson-storage-indexeddb@0.15.12
|
||||
- cojson-transport-ws@0.15.12
|
||||
|
||||
## 0.15.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
},
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.15.11",
|
||||
"version": "0.15.13",
|
||||
"dependencies": {
|
||||
"@manuscripts/prosemirror-recreate-steps": "^0.1.4",
|
||||
"@scure/base": "1.2.1",
|
||||
|
||||
@@ -47,6 +47,26 @@ describe("useCoState", () => {
|
||||
expect(result.current?.value).toBe("123");
|
||||
});
|
||||
|
||||
it("should return null on invalid id", async () => {
|
||||
const TestMap = co.map({
|
||||
value: z.string(),
|
||||
});
|
||||
|
||||
const account = await createJazzTestAccount({
|
||||
isCurrentActiveAccount: true,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useCoState(TestMap, "test", {}), {
|
||||
account,
|
||||
});
|
||||
|
||||
expect(result.current).toBeUndefined();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("should update the value when the coValue changes", async () => {
|
||||
const TestMap = co.map({
|
||||
value: z.string(),
|
||||
|
||||
@@ -279,8 +279,12 @@ export class JazzContextManager<
|
||||
},
|
||||
);
|
||||
|
||||
prevContext.node.syncManager.addPeer(currentAccountAsPeer);
|
||||
// Closing storage on the prevContext to avoid conflicting transactions and getting stuck on waitForAllCoValuesSync
|
||||
// The storage is reachable through currentContext using the connectedPeers
|
||||
prevContext.node.removeStorage();
|
||||
|
||||
currentContext.node.syncManager.addPeer(prevAccountAsPeer);
|
||||
prevContext.node.syncManager.addPeer(currentAccountAsPeer);
|
||||
|
||||
try {
|
||||
await this.props.onAnonymousAccountDiscarded?.(prevContext.me);
|
||||
|
||||
@@ -43,27 +43,35 @@ type SchemaField =
|
||||
| z.core.$ZodCatch<z.core.$ZodType>
|
||||
| (z.core.$ZodCustom<any, any> & { builtin: any });
|
||||
|
||||
export function schemaFieldToCoFieldDef(schema: SchemaField) {
|
||||
export function schemaFieldToCoFieldDef(
|
||||
schema: SchemaField,
|
||||
isOptional = false,
|
||||
) {
|
||||
if (isCoValueClass(schema)) {
|
||||
return coField.ref(schema);
|
||||
if (isOptional) {
|
||||
return coField.ref(schema, { optional: true });
|
||||
} else {
|
||||
return coField.ref(schema);
|
||||
}
|
||||
} else if (isCoValueSchema(schema)) {
|
||||
if (isAnyCoOptionalSchema(schema)) {
|
||||
return coField.ref(schema.getCoValueClass(), {
|
||||
optional: true,
|
||||
});
|
||||
}
|
||||
return coField.ref(schema.getCoValueClass());
|
||||
|
||||
if (isOptional) {
|
||||
return coField.ref(schema.getCoValueClass(), { optional: true });
|
||||
} else {
|
||||
return coField.ref(schema.getCoValueClass());
|
||||
}
|
||||
} else {
|
||||
if ("_zod" in schema) {
|
||||
if (schema._zod.def.type === "optional") {
|
||||
const inner = zodSchemaToCoSchemaOrKeepPrimitive(
|
||||
schema._zod.def.innerType,
|
||||
);
|
||||
if (isCoValueClass(inner)) {
|
||||
return coField.ref(inner, { optional: true });
|
||||
} else {
|
||||
return schemaFieldToCoFieldDef(inner);
|
||||
}
|
||||
return schemaFieldToCoFieldDef(inner, true);
|
||||
} else if (schema._zod.def.type === "string") {
|
||||
return coField.string;
|
||||
} else if (schema._zod.def.type === "number") {
|
||||
@@ -77,6 +85,7 @@ export function schemaFieldToCoFieldDef(schema: SchemaField) {
|
||||
} else if (schema._zod.def.type === "readonly") {
|
||||
return schemaFieldToCoFieldDef(
|
||||
(schema as unknown as ZodReadonly).def.innerType as SchemaField,
|
||||
isOptional,
|
||||
);
|
||||
} else if (schema._zod.def.type === "date") {
|
||||
return coField.optional.Date;
|
||||
@@ -86,6 +95,7 @@ export function schemaFieldToCoFieldDef(schema: SchemaField) {
|
||||
// Mostly to support z.json()
|
||||
return schemaFieldToCoFieldDef(
|
||||
(schema as unknown as ZodLazy).unwrap() as SchemaField,
|
||||
isOptional,
|
||||
);
|
||||
} else if (
|
||||
schema._zod.def.type === "default" ||
|
||||
@@ -98,6 +108,7 @@ export function schemaFieldToCoFieldDef(schema: SchemaField) {
|
||||
return schemaFieldToCoFieldDef(
|
||||
(schema as unknown as ZodDefault | ZodCatch).def
|
||||
.innerType as SchemaField,
|
||||
isOptional,
|
||||
);
|
||||
} else if (schema._zod.def.type === "literal") {
|
||||
if (
|
||||
@@ -129,7 +140,7 @@ export function schemaFieldToCoFieldDef(schema: SchemaField) {
|
||||
return coField.json();
|
||||
} else if (schema._zod.def.type === "custom") {
|
||||
if ("builtin" in schema) {
|
||||
return schemaFieldToCoFieldDef(schema.builtin);
|
||||
return schemaFieldToCoFieldDef(schema.builtin, isOptional);
|
||||
} else {
|
||||
throw new Error(`Unsupported custom zod type`);
|
||||
}
|
||||
@@ -137,9 +148,13 @@ export function schemaFieldToCoFieldDef(schema: SchemaField) {
|
||||
if (isUnionOfPrimitivesDeeply(schema)) {
|
||||
return coField.json();
|
||||
} else if (isUnionOfCoMapsDeeply(schema)) {
|
||||
return coField.ref<CoValueClass<CoMap>>(
|
||||
schemaUnionDiscriminatorFor(schema),
|
||||
);
|
||||
const result = schemaUnionDiscriminatorFor(schema);
|
||||
|
||||
if (isOptional) {
|
||||
return coField.ref<CoValueClass<CoMap>>(result, { optional: true });
|
||||
} else {
|
||||
return coField.ref<CoValueClass<CoMap>>(result);
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
"z.union()/z.discriminatedUnion() of mixed collaborative and non-collaborative types is not supported",
|
||||
|
||||
@@ -28,6 +28,10 @@ export class CoValueCoreSubscription {
|
||||
this.subscribeToState();
|
||||
this.listener("unavailable");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Unexpected error loading CoValue: ", error);
|
||||
this.listener("unavailable");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { StorageAPI } from "cojson";
|
||||
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
||||
import { beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import {
|
||||
@@ -32,6 +33,7 @@ import {
|
||||
getPeerConnectedToTestSyncServer,
|
||||
setupJazzTestSync,
|
||||
} from "../testing";
|
||||
import { createAsyncStorage, getDbPath } from "./testStorage";
|
||||
|
||||
const Crypto = await WasmCrypto.create();
|
||||
|
||||
@@ -40,12 +42,14 @@ class TestJazzContextManager<Acc extends Account> extends JazzContextManager<
|
||||
JazzContextManagerBaseProps<Acc> & {
|
||||
defaultProfileName?: string;
|
||||
AccountSchema?: AccountClass<Acc>;
|
||||
storage?: string;
|
||||
}
|
||||
> {
|
||||
async getNewContext(
|
||||
props: JazzContextManagerBaseProps<Acc> & {
|
||||
defaultProfileName?: string;
|
||||
AccountSchema?: AccountClass<Acc> & CoValueFromRaw<Acc>;
|
||||
storage?: string;
|
||||
},
|
||||
authProps?: JazzContextManagerAuthProps,
|
||||
) {
|
||||
@@ -58,6 +62,7 @@ class TestJazzContextManager<Acc extends Account> extends JazzContextManager<
|
||||
sessionProvider: randomSessionProvider,
|
||||
authSecretStorage: this.getAuthSecretStorage(),
|
||||
AccountSchema: props.AccountSchema,
|
||||
storage: await createAsyncStorage({ filename: props.storage }),
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -76,12 +81,14 @@ class TestJazzContextManager<Acc extends Account> extends JazzContextManager<
|
||||
describe("ContextManager", () => {
|
||||
let manager: TestJazzContextManager<Account>;
|
||||
let authSecretStorage: AuthSecretStorage;
|
||||
let storage: StorageAPI;
|
||||
|
||||
function getCurrentValue() {
|
||||
return manager.getCurrentValue() as JazzAuthContext<Account>;
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
storage = await createAsyncStorage({});
|
||||
KvStoreContext.getInstance().initialize(new InMemoryKVStore());
|
||||
authSecretStorage = new AuthSecretStorage();
|
||||
await authSecretStorage.clear();
|
||||
@@ -232,6 +239,78 @@ describe("ContextManager", () => {
|
||||
expect(onAnonymousAccountDiscarded).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("onAnonymousAccountDiscarded should not block the authentication when storage is active", async () => {
|
||||
const dbFilename = getDbPath();
|
||||
|
||||
const AccountRoot = co.map({
|
||||
value: z.string(),
|
||||
get transferredRoot(): z.ZodOptional<typeof AccountRoot> {
|
||||
return co.optional(AccountRoot);
|
||||
},
|
||||
});
|
||||
|
||||
let lastRootId: string | undefined;
|
||||
|
||||
const CustomAccount = co
|
||||
.account({
|
||||
root: AccountRoot,
|
||||
profile: co.profile(),
|
||||
})
|
||||
.withMigration(async (account) => {
|
||||
account.root = AccountRoot.create(
|
||||
{
|
||||
value: "Hello",
|
||||
},
|
||||
Group.create(this).makePublic(),
|
||||
);
|
||||
});
|
||||
|
||||
const customManager = new TestJazzContextManager<
|
||||
InstanceOfSchema<typeof CustomAccount>
|
||||
>();
|
||||
|
||||
await customManager.createContext({
|
||||
AccountSchema: anySchemaToCoSchema(CustomAccount),
|
||||
storage: dbFilename,
|
||||
onAnonymousAccountDiscarded: async (anonymousAccount) => {
|
||||
const anonymousAccountWithRoot = await anonymousAccount.ensureLoaded({
|
||||
resolve: { root: true },
|
||||
});
|
||||
|
||||
const me = await CustomAccount.getMe().ensureLoaded({
|
||||
resolve: { root: true },
|
||||
});
|
||||
|
||||
me.root.transferredRoot = anonymousAccountWithRoot.root;
|
||||
},
|
||||
});
|
||||
|
||||
const prevContextNode = customManager.getCurrentValue()!.node;
|
||||
|
||||
expect(prevContextNode.storage).toBeDefined();
|
||||
|
||||
const account = (
|
||||
customManager.getCurrentValue() as JazzAuthContext<
|
||||
InstanceOfSchema<typeof CustomAccount>
|
||||
>
|
||||
).me;
|
||||
|
||||
await customManager.authenticate({
|
||||
accountID: account.id,
|
||||
accountSecret: account._raw.core.node.getCurrentAgent().agentSecret,
|
||||
provider: "test",
|
||||
});
|
||||
|
||||
// The storage should be closed and set to undefined
|
||||
expect(prevContextNode.storage).toBeUndefined();
|
||||
|
||||
const me = await CustomAccount.getMe().ensureLoaded({
|
||||
resolve: { root: { transferredRoot: true } },
|
||||
});
|
||||
|
||||
expect(me.root.transferredRoot?.value).toBe("Hello");
|
||||
});
|
||||
|
||||
test("the migration should be applied correctly on existing accounts", async () => {
|
||||
const AccountRoot = co.map({
|
||||
value: z.string(),
|
||||
@@ -266,8 +345,6 @@ describe("ContextManager", () => {
|
||||
>
|
||||
).me;
|
||||
|
||||
console.log("before", account._refs.root?.id);
|
||||
|
||||
await customManager.authenticate({
|
||||
accountID: account.id,
|
||||
accountSecret: account._raw.core.node.getCurrentAgent().agentSecret,
|
||||
@@ -278,8 +355,6 @@ describe("ContextManager", () => {
|
||||
resolve: { root: true },
|
||||
});
|
||||
|
||||
console.log("after", me._refs.root?.id);
|
||||
|
||||
expect(me.root.id).toBe(lastRootId);
|
||||
});
|
||||
|
||||
|
||||
@@ -33,6 +33,129 @@ test("load a value", async () => {
|
||||
expect(john?.name).toBe("John");
|
||||
});
|
||||
|
||||
test("return null if id is invalid", async () => {
|
||||
const Person = co.map({
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const john = await Person.load("test");
|
||||
expect(john).toBeNull();
|
||||
});
|
||||
|
||||
test("load a missing optional value (co.optional)", async () => {
|
||||
const Dog = co.map({
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const Person = co.map({
|
||||
name: z.string(),
|
||||
dog: co.optional(Dog),
|
||||
});
|
||||
|
||||
const group = Group.create();
|
||||
const map = Person.create({ name: "John" }, group);
|
||||
group.addMember("everyone", "reader");
|
||||
|
||||
const alice = await createJazzTestAccount();
|
||||
|
||||
const john = await Person.load(map.id, {
|
||||
loadAs: alice,
|
||||
resolve: { dog: true },
|
||||
});
|
||||
|
||||
assert(john);
|
||||
|
||||
expect(john.name).toBe("John");
|
||||
expect(john.dog).toBeUndefined();
|
||||
});
|
||||
|
||||
test("load a missing optional value (z.optional)", async () => {
|
||||
const Dog = co.map({
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const Person = co.map({
|
||||
name: z.string(),
|
||||
dog: z.optional(Dog),
|
||||
});
|
||||
|
||||
const group = Group.create();
|
||||
const map = Person.create({ name: "John" }, group);
|
||||
group.addMember("everyone", "reader");
|
||||
|
||||
const alice = await createJazzTestAccount();
|
||||
|
||||
const john = await Person.load(map.id, {
|
||||
loadAs: alice,
|
||||
resolve: { dog: true },
|
||||
});
|
||||
|
||||
assert(john);
|
||||
|
||||
expect(john.name).toBe("John");
|
||||
expect(john.dog).toBeUndefined();
|
||||
});
|
||||
|
||||
test("load a missing optional value (Schema.optional)", async () => {
|
||||
const Dog = co.map({
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const Person = co.map({
|
||||
name: z.string(),
|
||||
dog: Dog.optional(),
|
||||
});
|
||||
|
||||
const group = Group.create();
|
||||
const map = Person.create({ name: "John" }, group);
|
||||
group.addMember("everyone", "reader");
|
||||
|
||||
const alice = await createJazzTestAccount();
|
||||
|
||||
const john = await Person.load(map.id, {
|
||||
loadAs: alice,
|
||||
resolve: { dog: true },
|
||||
});
|
||||
|
||||
assert(john);
|
||||
|
||||
expect(john.name).toBe("John");
|
||||
expect(john.dog).toBeUndefined();
|
||||
});
|
||||
|
||||
test("load a missing optional value (optional discrminatedUnion)", async () => {
|
||||
const Dog = co.map({
|
||||
type: z.literal("dog"),
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const Cat = co.map({
|
||||
type: z.literal("cat"),
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const Person = co.map({
|
||||
name: z.string(),
|
||||
pet: co.discriminatedUnion("type", [Dog, Cat]).optional(),
|
||||
});
|
||||
|
||||
const group = Group.create();
|
||||
const map = Person.create({ name: "John" }, group);
|
||||
group.addMember("everyone", "reader");
|
||||
|
||||
const alice = await createJazzTestAccount();
|
||||
|
||||
const john = await Person.load(map.id, {
|
||||
loadAs: alice,
|
||||
resolve: { pet: true },
|
||||
});
|
||||
|
||||
assert(john);
|
||||
|
||||
expect(john.name).toBe("John");
|
||||
expect(john.pet).toBeUndefined();
|
||||
});
|
||||
|
||||
test("retry an unavailable value", async () => {
|
||||
const Person = co.map({
|
||||
name: z.string(),
|
||||
|
||||
70
packages/jazz-tools/src/tools/tests/testStorage.ts
Normal file
70
packages/jazz-tools/src/tools/tests/testStorage.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { unlinkSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { SQLiteDatabaseDriverAsync, getSqliteStorageAsync } from "cojson";
|
||||
import Database, { type Database as DatabaseT } from "libsql";
|
||||
import { onTestFinished } from "vitest";
|
||||
|
||||
class LibSQLSqliteAsyncDriver implements SQLiteDatabaseDriverAsync {
|
||||
private readonly db: DatabaseT;
|
||||
|
||||
constructor(filename: string) {
|
||||
this.db = new Database(filename, {});
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
await this.db.pragma("journal_mode = WAL");
|
||||
}
|
||||
|
||||
async run(sql: string, params: unknown[]) {
|
||||
this.db.prepare(sql).run(params);
|
||||
}
|
||||
|
||||
async query<T>(sql: string, params: unknown[]): Promise<T[]> {
|
||||
return this.db.prepare(sql).all(params) as T[];
|
||||
}
|
||||
|
||||
async get<T>(sql: string, params: unknown[]): Promise<T | undefined> {
|
||||
return this.db.prepare(sql).get(params) as T | undefined;
|
||||
}
|
||||
|
||||
async transaction(callback: () => unknown) {
|
||||
await this.run("BEGIN TRANSACTION", []);
|
||||
|
||||
try {
|
||||
await callback();
|
||||
await this.run("COMMIT", []);
|
||||
} catch (error) {
|
||||
await this.run("ROLLBACK", []);
|
||||
}
|
||||
}
|
||||
|
||||
async closeDb() {
|
||||
this.db.close();
|
||||
}
|
||||
}
|
||||
|
||||
export async function createAsyncStorage({ filename }: { filename?: string }) {
|
||||
const storage = await getSqliteStorageAsync(
|
||||
new LibSQLSqliteAsyncDriver(getDbPath(filename)),
|
||||
);
|
||||
|
||||
onTestFinished(() => {
|
||||
storage.close();
|
||||
});
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
export function getDbPath(defaultDbPath?: string) {
|
||||
const dbPath = defaultDbPath ?? join(tmpdir(), `test-${randomUUID()}.db`);
|
||||
|
||||
if (!defaultDbPath) {
|
||||
onTestFinished(() => {
|
||||
unlinkSync(dbPath);
|
||||
});
|
||||
}
|
||||
|
||||
return dbPath;
|
||||
}
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -1772,19 +1772,19 @@ importers:
|
||||
specifier: ^0.25.5
|
||||
version: 0.25.8(effect@3.11.9)
|
||||
cojson:
|
||||
specifier: workspace:0.15.11
|
||||
specifier: workspace:0.15.13
|
||||
version: link:../cojson
|
||||
cojson-storage-sqlite:
|
||||
specifier: workspace:0.15.11
|
||||
specifier: workspace:0.15.13
|
||||
version: link:../cojson-storage-sqlite
|
||||
cojson-transport-ws:
|
||||
specifier: workspace:0.15.11
|
||||
specifier: workspace:0.15.13
|
||||
version: link:../cojson-transport-ws
|
||||
effect:
|
||||
specifier: ^3.6.5
|
||||
version: 3.11.9
|
||||
jazz-tools:
|
||||
specifier: workspace:0.15.11
|
||||
specifier: workspace:0.15.13
|
||||
version: link:../jazz-tools
|
||||
ws:
|
||||
specifier: ^8.14.2
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# jazz-react-tailwind-starter
|
||||
|
||||
## 0.0.133
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c76ff8]
|
||||
- jazz-tools@0.15.13
|
||||
|
||||
## 0.0.132
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1c1b0c]
|
||||
- Updated dependencies [cf4ad72]
|
||||
- jazz-tools@0.15.12
|
||||
|
||||
## 0.0.131
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-react-passkey-auth-starter",
|
||||
"private": true,
|
||||
"version": "0.0.131",
|
||||
"version": "0.0.133",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# svelte-passkey-auth
|
||||
|
||||
## 0.0.107
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6c76ff8]
|
||||
- jazz-tools@0.15.13
|
||||
|
||||
## 0.0.106
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d1c1b0c]
|
||||
- Updated dependencies [cf4ad72]
|
||||
- jazz-tools@0.15.12
|
||||
|
||||
## 0.0.105
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "svelte-passkey-auth",
|
||||
"version": "0.0.105",
|
||||
"version": "0.0.107",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user