@keyneom/sync-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/dist/auth/google-web/index.d.ts +53 -0
  4. package/dist/auth/google-web/index.d.ts.map +1 -0
  5. package/dist/auth/google-web/index.js +115 -0
  6. package/dist/auth/google-web/index.js.map +1 -0
  7. package/dist/core/errors.d.ts +11 -0
  8. package/dist/core/errors.d.ts.map +1 -0
  9. package/dist/core/errors.js +19 -0
  10. package/dist/core/errors.js.map +1 -0
  11. package/dist/core/index.d.ts +3 -0
  12. package/dist/core/index.d.ts.map +1 -0
  13. package/dist/core/index.js +3 -0
  14. package/dist/core/index.js.map +1 -0
  15. package/dist/core/types.d.ts +52 -0
  16. package/dist/core/types.d.ts.map +1 -0
  17. package/dist/core/types.js +2 -0
  18. package/dist/core/types.js.map +1 -0
  19. package/dist/crypto/base64url.d.ts +3 -0
  20. package/dist/crypto/base64url.d.ts.map +1 -0
  21. package/dist/crypto/base64url.js +34 -0
  22. package/dist/crypto/base64url.js.map +1 -0
  23. package/dist/crypto/canonical.d.ts +3 -0
  24. package/dist/crypto/canonical.d.ts.map +1 -0
  25. package/dist/crypto/canonical.js +30 -0
  26. package/dist/crypto/canonical.js.map +1 -0
  27. package/dist/crypto/envelope.d.ts +31 -0
  28. package/dist/crypto/envelope.d.ts.map +1 -0
  29. package/dist/crypto/envelope.js +109 -0
  30. package/dist/crypto/envelope.js.map +1 -0
  31. package/dist/crypto/index.d.ts +6 -0
  32. package/dist/crypto/index.d.ts.map +1 -0
  33. package/dist/crypto/index.js +6 -0
  34. package/dist/crypto/index.js.map +1 -0
  35. package/dist/crypto/profiles.d.ts +73 -0
  36. package/dist/crypto/profiles.d.ts.map +1 -0
  37. package/dist/crypto/profiles.js +48 -0
  38. package/dist/crypto/profiles.js.map +1 -0
  39. package/dist/crypto/runtime.d.ts +11 -0
  40. package/dist/crypto/runtime.d.ts.map +1 -0
  41. package/dist/crypto/runtime.js +57 -0
  42. package/dist/crypto/runtime.js.map +1 -0
  43. package/dist/index.d.ts +4 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +4 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/keys/web-passkey/index.d.ts +34 -0
  48. package/dist/keys/web-passkey/index.d.ts.map +1 -0
  49. package/dist/keys/web-passkey/index.js +186 -0
  50. package/dist/keys/web-passkey/index.js.map +1 -0
  51. package/dist/snapshot/controller.d.ts +23 -0
  52. package/dist/snapshot/controller.d.ts.map +1 -0
  53. package/dist/snapshot/controller.js +150 -0
  54. package/dist/snapshot/controller.js.map +1 -0
  55. package/dist/snapshot/index.d.ts +2 -0
  56. package/dist/snapshot/index.d.ts.map +1 -0
  57. package/dist/snapshot/index.js +2 -0
  58. package/dist/snapshot/index.js.map +1 -0
  59. package/dist/snapshot/lifecycle.d.ts +11 -0
  60. package/dist/snapshot/lifecycle.d.ts.map +1 -0
  61. package/dist/snapshot/lifecycle.js +37 -0
  62. package/dist/snapshot/lifecycle.js.map +1 -0
  63. package/dist/stores/google-drive/index.d.ts +43 -0
  64. package/dist/stores/google-drive/index.d.ts.map +1 -0
  65. package/dist/stores/google-drive/index.js +136 -0
  66. package/dist/stores/google-drive/index.js.map +1 -0
  67. package/fixtures/v1/easybc-web-android-gzip.json +41 -0
  68. package/fixtures/v1/easybc-web-uncompressed.json +35 -0
  69. package/fixtures/v1/failures.json +42 -0
  70. package/fixtures/v1/family-chores-web-uncompressed.json +73 -0
  71. package/fixtures/v1/profiles.json +51 -0
  72. package/package.json +76 -0
@@ -0,0 +1,150 @@
1
+ import { SyncKitError } from "../core/errors.js";
2
+ export function createSnapshotSync(options) {
3
+ let operationTail = Promise.resolve();
4
+ let operationCount = 0;
5
+ let queuedChange = null;
6
+ function operationInProgress() {
7
+ return operationCount > 0;
8
+ }
9
+ function runExclusive(operation) {
10
+ operationCount += 1;
11
+ const result = operationTail.then(operation);
12
+ operationTail = result.then(() => undefined, () => undefined);
13
+ return result.finally(() => {
14
+ operationCount -= 1;
15
+ });
16
+ }
17
+ async function findRequired(authorization) {
18
+ const existing = await options.cloudStore.find(options.appId, authorization);
19
+ if (!existing) {
20
+ throw new SyncKitError("not-found", `No ${options.appId} encrypted snapshot was found.`);
21
+ }
22
+ return existing;
23
+ }
24
+ async function setupNow() {
25
+ const authorization = await options.authorizationProvider.authorize();
26
+ if (await options.cloudStore.find(options.appId, authorization)) {
27
+ throw new SyncKitError("state", `A ${options.appId} encrypted snapshot already exists.`);
28
+ }
29
+ const local = await options.readLocal();
30
+ const created = await options.keyProvider.create({ appId: options.appId });
31
+ const envelope = await options.envelopeCrypto.encrypt(local, created.key, created.metadata);
32
+ const fileId = await options.cloudStore.write(options.appId, envelope, authorization);
33
+ return {
34
+ operation: "setup",
35
+ outcome: "created",
36
+ fileId,
37
+ syncedAt: options.envelopeUpdatedAt(envelope),
38
+ value: local,
39
+ };
40
+ }
41
+ async function mergeNow(operation) {
42
+ const authorization = await options.authorizationProvider.authorize();
43
+ const existing = await findRequired(authorization);
44
+ const key = await options.keyProvider.unlock(existing.envelope);
45
+ let remote;
46
+ try {
47
+ remote = await options.envelopeCrypto.decrypt(existing.envelope, key);
48
+ }
49
+ catch (error) {
50
+ options.keyProvider.clear();
51
+ throw error;
52
+ }
53
+ const local = await options.readLocal();
54
+ const merged = options.codec.merge(local, remote);
55
+ const cloudChanged = options.codec.fingerprint(merged) !== options.codec.fingerprint(remote);
56
+ let syncedAt = options.envelopeUpdatedAt(existing.envelope);
57
+ if (cloudChanged) {
58
+ const metadata = options.envelopeCrypto.metadataFromEnvelope(existing.envelope);
59
+ const envelope = await options.envelopeCrypto.encrypt(merged, key, metadata);
60
+ await options.cloudStore.write(options.appId, envelope, authorization, existing.fileId);
61
+ syncedAt = options.envelopeUpdatedAt(envelope);
62
+ }
63
+ await options.applyMerged(merged);
64
+ return {
65
+ operation,
66
+ outcome: cloudChanged ? "merged" : "unchanged",
67
+ fileId: existing.fileId,
68
+ syncedAt,
69
+ value: merged,
70
+ };
71
+ }
72
+ async function resetNow() {
73
+ const authorization = await options.authorizationProvider.authorize();
74
+ const existing = await findRequired(authorization);
75
+ options.keyProvider.clear();
76
+ const local = await options.readLocal();
77
+ const created = await options.keyProvider.create({ appId: options.appId });
78
+ const envelope = await options.envelopeCrypto.encrypt(local, created.key, created.metadata);
79
+ await options.cloudStore.write(options.appId, envelope, authorization, existing.fileId);
80
+ return {
81
+ operation: "reset",
82
+ outcome: "reset",
83
+ fileId: existing.fileId,
84
+ syncedAt: options.envelopeUpdatedAt(envelope),
85
+ value: local,
86
+ };
87
+ }
88
+ function setup() {
89
+ return runExclusive(setupNow);
90
+ }
91
+ function enable() {
92
+ return runExclusive(() => mergeNow("enable"));
93
+ }
94
+ function sync(reason) {
95
+ if (operationInProgress()) {
96
+ if (reason !== "change") {
97
+ return Promise.resolve({
98
+ operation: "sync",
99
+ outcome: "coalesced",
100
+ fileId: null,
101
+ syncedAt: null,
102
+ value: null,
103
+ });
104
+ }
105
+ if (queuedChange)
106
+ return queuedChange;
107
+ const pending = runExclusive(() => mergeNow("sync"));
108
+ queuedChange = pending;
109
+ void pending.then(() => {
110
+ if (queuedChange === pending)
111
+ queuedChange = null;
112
+ }, () => {
113
+ if (queuedChange === pending)
114
+ queuedChange = null;
115
+ });
116
+ return pending;
117
+ }
118
+ return runExclusive(() => mergeNow("sync"));
119
+ }
120
+ function reset() {
121
+ return runExclusive(resetNow);
122
+ }
123
+ function deleteSnapshot() {
124
+ return runExclusive(async () => {
125
+ const authorization = await options.authorizationProvider.authorize();
126
+ const existing = await options.cloudStore.find(options.appId, authorization);
127
+ if (existing) {
128
+ if (!options.cloudStore.delete) {
129
+ throw new SyncKitError("configuration", "This cloud store does not support deletion.");
130
+ }
131
+ await options.cloudStore.delete(options.appId, existing.fileId, authorization);
132
+ }
133
+ lock();
134
+ });
135
+ }
136
+ function lock() {
137
+ options.keyProvider.clear();
138
+ options.authorizationProvider.clear();
139
+ }
140
+ return {
141
+ setup,
142
+ enable,
143
+ sync,
144
+ reset,
145
+ delete: deleteSnapshot,
146
+ lock,
147
+ operationInProgress,
148
+ };
149
+ }
150
+ //# sourceMappingURL=controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../src/snapshot/controller.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAwBjD,MAAM,UAAU,kBAAkB,CAChC,OAA2C;IAE3C,IAAI,aAAa,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IACrD,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,YAAY,GAAkC,IAAI,CAAC;IAEvD,SAAS,mBAAmB;QAC1B,OAAO,cAAc,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,SAAS,YAAY,CAAI,SAA2B;QAClD,cAAc,IAAI,CAAC,CAAC;QACpB,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7C,aAAa,GAAG,MAAM,CAAC,IAAI,CACzB,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CAChB,CAAC;QACF,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;YACzB,cAAc,IAAI,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,UAAU,YAAY,CACzB,aAAgB;QAEhB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAC5C,OAAO,CAAC,KAAK,EACb,aAAa,CACd,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,MAAM,OAAO,CAAC,KAAK,gCAAgC,CACpD,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,UAAU,QAAQ;QACrB,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,SAAS,EAAE,CAAC;QACtE,IAAI,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,YAAY,CACpB,OAAO,EACP,KAAK,OAAO,CAAC,KAAK,qCAAqC,CACxD,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,OAAO,CACnD,KAAK,EACL,OAAO,CAAC,GAAG,EACX,OAAO,CAAC,QAAQ,CACjB,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,KAAK,CAC3C,OAAO,CAAC,KAAK,EACb,QAAQ,EACR,aAAa,CACd,CAAC;QACF,OAAO;YACL,SAAS,EAAE,OAAO;YAClB,OAAO,EAAE,SAAS;YAClB,MAAM;YACN,QAAQ,EAAE,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC;YAC7C,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;IAED,KAAK,UAAU,QAAQ,CACrB,SAA4B;QAE5B,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,SAAS,EAAE,CAAC;QACtE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChE,IAAI,MAAS,CAAC;QACd,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACxE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YAC5B,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAClD,MAAM,YAAY,GAChB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1E,IAAI,QAAQ,GAAG,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC5D,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,oBAAoB,CAC1D,QAAQ,CAAC,QAAQ,CAClB,CAAC;YACF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,OAAO,CACnD,MAAM,EACN,GAAG,EACH,QAAQ,CACT,CAAC;YACF,MAAM,OAAO,CAAC,UAAU,CAAC,KAAK,CAC5B,OAAO,CAAC,KAAK,EACb,QAAQ,EACR,aAAa,EACb,QAAQ,CAAC,MAAM,CAChB,CAAC;YACF,QAAQ,GAAG,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC;QACD,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,OAAO;YACL,SAAS;YACT,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW;YAC9C,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,QAAQ;YACR,KAAK,EAAE,MAAM;SACd,CAAC;IACJ,CAAC;IAED,KAAK,UAAU,QAAQ;QACrB,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,SAAS,EAAE,CAAC;QACtE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;QACnD,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,OAAO,CACnD,KAAK,EACL,OAAO,CAAC,GAAG,EACX,OAAO,CAAC,QAAQ,CACjB,CAAC;QACF,MAAM,OAAO,CAAC,UAAU,CAAC,KAAK,CAC5B,OAAO,CAAC,KAAK,EACb,QAAQ,EACR,aAAa,EACb,QAAQ,CAAC,MAAM,CAChB,CAAC;QACF,OAAO;YACL,SAAS,EAAE,OAAO;YAClB,OAAO,EAAE,OAAO;YAChB,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,QAAQ,EAAE,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC;YAC7C,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;IAED,SAAS,KAAK;QACZ,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,SAAS,MAAM;QACb,OAAO,YAAY,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,SAAS,IAAI,CAAC,MAAkB;QAC9B,IAAI,mBAAmB,EAAE,EAAE,CAAC;YAC1B,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACxB,OAAO,OAAO,CAAC,OAAO,CAAC;oBACrB,SAAS,EAAE,MAAM;oBACjB,OAAO,EAAE,WAAW;oBACpB,MAAM,EAAE,IAAI;oBACZ,QAAQ,EAAE,IAAI;oBACd,KAAK,EAAE,IAAI;iBACZ,CAAC,CAAC;YACL,CAAC;YACD,IAAI,YAAY;gBAAE,OAAO,YAAY,CAAC;YACtC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACrD,YAAY,GAAG,OAAO,CAAC;YACvB,KAAK,OAAO,CAAC,IAAI,CACf,GAAG,EAAE;gBACH,IAAI,YAAY,KAAK,OAAO;oBAAE,YAAY,GAAG,IAAI,CAAC;YACpD,CAAC,EACD,GAAG,EAAE;gBACH,IAAI,YAAY,KAAK,OAAO;oBAAE,YAAY,GAAG,IAAI,CAAC;YACpD,CAAC,CACF,CAAC;YACF,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,OAAO,YAAY,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,SAAS,KAAK;QACZ,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,SAAS,cAAc;QACrB,OAAO,YAAY,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,SAAS,EAAE,CAAC;YACtE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAC5C,OAAO,CAAC,KAAK,EACb,aAAa,CACd,CAAC;YACF,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;oBAC/B,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,6CAA6C,CAC9C,CAAC;gBACJ,CAAC;gBACD,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,CAC7B,OAAO,CAAC,KAAK,EACb,QAAQ,CAAC,MAAM,EACf,aAAa,CACd,CAAC;YACJ,CAAC;YACD,IAAI,EAAE,CAAC;QACT,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,IAAI;QACX,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QAC5B,OAAO,CAAC,qBAAqB,CAAC,KAAK,EAAE,CAAC;IACxC,CAAC;IAED,OAAO;QACL,KAAK;QACL,MAAM;QACN,IAAI;QACJ,KAAK;QACL,MAAM,EAAE,cAAc;QACtB,IAAI;QACJ,mBAAmB;KACpB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./controller.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/snapshot/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./controller.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/snapshot/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { SnapshotSyncController } from "./controller.js";
2
+ export type LifecycleBindingOptions = {
3
+ backgroundGraceMs?: number;
4
+ syncOnForeground?: boolean;
5
+ minimumBackgroundMs?: number;
6
+ window?: Window;
7
+ document?: Document;
8
+ now?: () => number;
9
+ };
10
+ export declare function bindWebLifecycle<T>(controller: SnapshotSyncController<T>, options?: LifecycleBindingOptions): () => void;
11
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/snapshot/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAE9D,MAAM,MAAM,uBAAuB,GAAG;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,UAAU,EAAE,sBAAsB,CAAC,CAAC,CAAC,EACrC,OAAO,GAAE,uBAA4B,GACpC,MAAM,IAAI,CA+CZ"}
@@ -0,0 +1,37 @@
1
+ export function bindWebLifecycle(controller, options = {}) {
2
+ const windowImplementation = options.window ?? window;
3
+ const documentImplementation = options.document ?? document;
4
+ const now = options.now ?? Date.now;
5
+ let hiddenAt = null;
6
+ let lockTimer = null;
7
+ const cancelTimer = () => {
8
+ if (lockTimer !== null)
9
+ clearTimeout(lockTimer);
10
+ lockTimer = null;
11
+ };
12
+ const visibilityChanged = () => {
13
+ if (documentImplementation.visibilityState === "hidden") {
14
+ hiddenAt = now();
15
+ cancelTimer();
16
+ lockTimer = setTimeout(() => controller.lock(), options.backgroundGraceMs ?? 15 * 60_000);
17
+ return;
18
+ }
19
+ cancelTimer();
20
+ const timeAway = hiddenAt === null ? 0 : now() - hiddenAt;
21
+ hiddenAt = null;
22
+ if (options.syncOnForeground &&
23
+ timeAway >= (options.minimumBackgroundMs ?? 60_000) &&
24
+ !controller.operationInProgress()) {
25
+ void controller.sync("foreground");
26
+ }
27
+ };
28
+ const pageHidden = () => controller.lock();
29
+ documentImplementation.addEventListener("visibilitychange", visibilityChanged);
30
+ windowImplementation.addEventListener("pagehide", pageHidden);
31
+ return () => {
32
+ cancelTimer();
33
+ documentImplementation.removeEventListener("visibilitychange", visibilityChanged);
34
+ windowImplementation.removeEventListener("pagehide", pageHidden);
35
+ };
36
+ }
37
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/snapshot/lifecycle.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,gBAAgB,CAC9B,UAAqC,EACrC,UAAmC,EAAE;IAErC,MAAM,oBAAoB,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC;IACtD,MAAM,sBAAsB,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAC5D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,SAAS,GAAyC,IAAI,CAAC;IAE3D,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,IAAI,SAAS,KAAK,IAAI;YAAE,YAAY,CAAC,SAAS,CAAC,CAAC;QAChD,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC,CAAC;IACF,MAAM,iBAAiB,GAAG,GAAG,EAAE;QAC7B,IAAI,sBAAsB,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;YACxD,QAAQ,GAAG,GAAG,EAAE,CAAC;YACjB,WAAW,EAAE,CAAC;YACd,SAAS,GAAG,UAAU,CACpB,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,EACvB,OAAO,CAAC,iBAAiB,IAAI,EAAE,GAAG,MAAM,CACzC,CAAC;YACF,OAAO;QACT,CAAC;QACD,WAAW,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC;QAC1D,QAAQ,GAAG,IAAI,CAAC;QAChB,IACE,OAAO,CAAC,gBAAgB;YACxB,QAAQ,IAAI,CAAC,OAAO,CAAC,mBAAmB,IAAI,MAAM,CAAC;YACnD,CAAC,UAAU,CAAC,mBAAmB,EAAE,EACjC,CAAC;YACD,KAAK,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAC3C,sBAAsB,CAAC,gBAAgB,CACrC,kBAAkB,EAClB,iBAAiB,CAClB,CAAC;IACF,oBAAoB,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAE9D,OAAO,GAAG,EAAE;QACV,WAAW,EAAE,CAAC;QACd,sBAAsB,CAAC,mBAAmB,CACxC,kBAAkB,EAClB,iBAAiB,CAClB,CAAC;QACF,oBAAoB,CAAC,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACnE,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { Authorization, CloudStore, StoredEnvelope } from "../../core/types.js";
2
+ export type DriveObject = {
3
+ fileId: string;
4
+ name: string;
5
+ modifiedTime?: string;
6
+ };
7
+ export type GoogleDriveAppDataOptions = {
8
+ fetch?: typeof fetch;
9
+ randomUUID?: () => string;
10
+ onUnauthorized?: () => void;
11
+ };
12
+ export type DriveContent = string | Blob | ArrayBuffer | Uint8Array<ArrayBuffer>;
13
+ export declare class GoogleDriveAppDataStore {
14
+ private readonly options;
15
+ constructor(options?: GoogleDriveAppDataOptions);
16
+ find(name: string, authorization: Authorization): Promise<DriveObject | null>;
17
+ readText(fileId: string, authorization: Authorization): Promise<string>;
18
+ readBytes(fileId: string, authorization: Authorization): Promise<Uint8Array>;
19
+ write(name: string, content: DriveContent, authorization: Authorization, options?: {
20
+ existingId?: string;
21
+ contentType?: string;
22
+ }): Promise<string>;
23
+ delete(fileId: string, authorization: Authorization): Promise<void>;
24
+ private request;
25
+ private randomUUID;
26
+ }
27
+ export type GoogleDriveSnapshotStoreOptions<E> = {
28
+ appId: string;
29
+ filename: string;
30
+ parse(value: string): E;
31
+ serialize?(value: E): string;
32
+ drive?: GoogleDriveAppDataStore;
33
+ };
34
+ export declare class GoogleDriveSnapshotStore<E> implements CloudStore<E, Authorization> {
35
+ private readonly options;
36
+ private readonly drive;
37
+ constructor(options: GoogleDriveSnapshotStoreOptions<E>);
38
+ find(appId: string, authorization: Authorization): Promise<StoredEnvelope<E> | null>;
39
+ write(appId: string, envelope: E, authorization: Authorization, existingId?: string): Promise<string>;
40
+ delete(appId: string, fileId: string, authorization: Authorization): Promise<void>;
41
+ private assertAppId;
42
+ }
43
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/stores/google-drive/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,cAAc,EACf,MAAM,qBAAqB,CAAC;AAM7B,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,IAAI,GACJ,WAAW,GACX,UAAU,CAAC,WAAW,CAAC,CAAC;AAE5B,qBAAa,uBAAuB;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,GAAE,yBAA8B;IAE9D,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA0BxB,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,MAAM,CAAC;IAQZ,SAAS,CACb,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,UAAU,CAAC;IAQhB,KAAK,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EACrB,aAAa,EAAE,aAAa,EAC5B,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAO,GAC1D,OAAO,CAAC,MAAM,CAAC;IAyCZ,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;YAQ3D,OAAO;IA8BrB,OAAO,CAAC,UAAU;CAcnB;AAED,MAAM,MAAM,+BAA+B,CAAC,CAAC,IAAI;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC;IACxB,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,uBAAuB,CAAC;CACjC,CAAC;AAEF,qBAAa,wBAAwB,CAAC,CAAC,CACrC,YAAW,UAAU,CAAC,CAAC,EAAE,aAAa,CAAC;IAI3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;gBAEnB,OAAO,EAAE,+BAA+B,CAAC,CAAC,CAAC;IAIlE,IAAI,CACR,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAYpC,KAAK,CACH,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,EACX,aAAa,EAAE,aAAa,EAC5B,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC;IAaZ,MAAM,CACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,IAAI,CAAC;IAKhB,OAAO,CAAC,WAAW;CAQpB"}
@@ -0,0 +1,136 @@
1
+ import { SyncKitError } from "../../core/errors.js";
2
+ const DRIVE_API = "https://www.googleapis.com/drive/v3/files";
3
+ const DRIVE_UPLOAD_API = "https://www.googleapis.com/upload/drive/v3/files";
4
+ export class GoogleDriveAppDataStore {
5
+ options;
6
+ constructor(options = {}) {
7
+ this.options = options;
8
+ }
9
+ async find(name, authorization) {
10
+ const params = new URLSearchParams({
11
+ spaces: "appDataFolder",
12
+ q: `name = '${escapeDriveQuery(name)}' and trashed = false`,
13
+ fields: "files(id,name,modifiedTime)",
14
+ pageSize: "1",
15
+ });
16
+ const response = await this.request(`${DRIVE_API}?${params}`, authorization);
17
+ const value = (await response.json());
18
+ const file = value.files?.[0];
19
+ return file
20
+ ? {
21
+ fileId: file.id,
22
+ name: file.name ?? name,
23
+ ...(file.modifiedTime === undefined
24
+ ? {}
25
+ : { modifiedTime: file.modifiedTime }),
26
+ }
27
+ : null;
28
+ }
29
+ async readText(fileId, authorization) {
30
+ const response = await this.request(`${DRIVE_API}/${encodeURIComponent(fileId)}?alt=media`, authorization);
31
+ return response.text();
32
+ }
33
+ async readBytes(fileId, authorization) {
34
+ const response = await this.request(`${DRIVE_API}/${encodeURIComponent(fileId)}?alt=media`, authorization);
35
+ return new Uint8Array(await response.arrayBuffer());
36
+ }
37
+ async write(name, content, authorization, options = {}) {
38
+ const contentType = options.contentType ?? "application/octet-stream";
39
+ if (options.existingId) {
40
+ await this.request(`${DRIVE_UPLOAD_API}/${encodeURIComponent(options.existingId)}?uploadType=media&fields=id`, authorization, {
41
+ method: "PATCH",
42
+ headers: { "Content-Type": contentType },
43
+ body: content,
44
+ });
45
+ return options.existingId;
46
+ }
47
+ const boundary = `sync-kit-${this.randomUUID()}`;
48
+ const body = new Blob([
49
+ `--${boundary}\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n`,
50
+ JSON.stringify({ name, parents: ["appDataFolder"] }),
51
+ `\r\n--${boundary}\r\nContent-Type: ${contentType}\r\n\r\n`,
52
+ content,
53
+ `\r\n--${boundary}--`,
54
+ ]);
55
+ const response = await this.request(`${DRIVE_UPLOAD_API}?uploadType=multipart&fields=id`, authorization, {
56
+ method: "POST",
57
+ headers: { "Content-Type": `multipart/related; boundary=${boundary}` },
58
+ body,
59
+ });
60
+ const created = (await response.json());
61
+ if (!created.id) {
62
+ throw new SyncKitError("provider", "Google Drive did not return a file ID.");
63
+ }
64
+ return created.id;
65
+ }
66
+ async delete(fileId, authorization) {
67
+ await this.request(`${DRIVE_API}/${encodeURIComponent(fileId)}`, authorization, { method: "DELETE" });
68
+ }
69
+ async request(url, authorization, init = {}) {
70
+ const fetchImplementation = this.options.fetch ?? globalThis.fetch;
71
+ if (!fetchImplementation) {
72
+ throw new SyncKitError("configuration", "A Fetch API implementation is required.");
73
+ }
74
+ const headers = new Headers(init.headers);
75
+ headers.set("Authorization", `Bearer ${authorization.accessToken}`);
76
+ const response = await fetchImplementation(url, {
77
+ ...init,
78
+ headers,
79
+ });
80
+ if (!response.ok) {
81
+ if (response.status === 401)
82
+ this.options.onUnauthorized?.();
83
+ const detail = (await response.text()).slice(0, 400);
84
+ throw new SyncKitError(response.status === 404 ? "not-found" : "provider", `Google Drive request failed (${response.status}). ${detail}`, { status: response.status });
85
+ }
86
+ return response;
87
+ }
88
+ randomUUID() {
89
+ const implementation = this.options.randomUUID ??
90
+ (typeof crypto === "undefined"
91
+ ? undefined
92
+ : crypto.randomUUID.bind(crypto));
93
+ if (!implementation) {
94
+ throw new SyncKitError("configuration", "Secure UUID generation is unavailable.");
95
+ }
96
+ return implementation();
97
+ }
98
+ }
99
+ export class GoogleDriveSnapshotStore {
100
+ options;
101
+ drive;
102
+ constructor(options) {
103
+ this.options = options;
104
+ this.drive = options.drive ?? new GoogleDriveAppDataStore();
105
+ }
106
+ async find(appId, authorization) {
107
+ this.assertAppId(appId);
108
+ const found = await this.drive.find(this.options.filename, authorization);
109
+ if (!found)
110
+ return null;
111
+ return {
112
+ fileId: found.fileId,
113
+ envelope: this.options.parse(await this.drive.readText(found.fileId, authorization)),
114
+ };
115
+ }
116
+ write(appId, envelope, authorization, existingId) {
117
+ this.assertAppId(appId);
118
+ return this.drive.write(this.options.filename, this.options.serialize?.(envelope) ?? JSON.stringify(envelope), authorization, {
119
+ ...(existingId === undefined ? {} : { existingId }),
120
+ contentType: "application/json",
121
+ });
122
+ }
123
+ async delete(appId, fileId, authorization) {
124
+ this.assertAppId(appId);
125
+ await this.drive.delete(fileId, authorization);
126
+ }
127
+ assertAppId(appId) {
128
+ if (appId !== this.options.appId) {
129
+ throw new SyncKitError("compatibility", `The ${this.options.appId} store rejected app ID ${appId}.`);
130
+ }
131
+ }
132
+ }
133
+ function escapeDriveQuery(value) {
134
+ return value.replaceAll("\\", "\\\\").replaceAll("'", "\\'");
135
+ }
136
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/stores/google-drive/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ {
2
+ "provenance": "Shared by live EasyBC web crypto.test.ts and Android SyncCryptoTest.decryptsSharedGzipCryptoVector",
3
+ "secret": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8",
4
+ "payload": {
5
+ "schemaVersion": 1,
6
+ "exportedAt": "2026-06-22T12:00:00Z",
7
+ "planner": {
8
+ "value": {
9
+ "ageYears": 38
10
+ },
11
+ "updatedAt": "2026-06-22T12:00:00Z"
12
+ },
13
+ "periodRecords": [],
14
+ "deletedPeriodStarts": {},
15
+ "calendarDayLogs": {
16
+ "2026-06-22": {
17
+ "notes": "cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector cross-platform gzip vector ",
18
+ "updatedAt": "2026-06-22T12:00:00Z"
19
+ }
20
+ },
21
+ "voluntaryAbstinenceDates": {},
22
+ "voluntaryAbstinenceUpdatedAt": {},
23
+ "deletedVoluntaryAbstinenceDates": {},
24
+ "ecJournal": {
25
+ "value": false,
26
+ "updatedAt": "2026-06-22T12:00:00Z"
27
+ }
28
+ },
29
+ "envelope": {
30
+ "schemaVersion": 1,
31
+ "algorithm": "AES-256-GCM+HKDF-SHA-256",
32
+ "compression": "gzip",
33
+ "credentialId": "credential",
34
+ "rpId": "keyneom.github.io",
35
+ "prfInput": "AA",
36
+ "kdfSalt": "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8",
37
+ "nonce": "QEFCQ0RFRkdISUpL",
38
+ "ciphertext": "LMBOEaK5ATYQxI26eKGwIdJ_ELsBJ8rf76MIXyxVsT3kN1K3qY42h07AZHOYkztpJYdhERCZmbG2j_Pd1zhqKRMIMdrj_-pBd6DljWZU0uD7d5rHWCbyAqudt_psdPSHm47MuQauJTsCjVmEkPNKCZZNOZkYnceNyC9MZQM_tY15jJLsHEdOnQS43zyNhv180UmM9POJcsaWBAG6yIfDRDpd2b1IpPuxmIAV3GLMYLiNHbJ4yDUX6PRYFhzI-Hh18rggXBENhWfq9kZ3hBpPKGkms-j4MHFIGhg_o3GY_rZTHCzq3phTdD3Mo4iSWf7D6FXezQP6H_jwyhDE0ydJyTjNfIPPyCESZtc",
39
+ "updatedAt": "2026-06-22T12:00:00Z"
40
+ }
41
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "provenance": "EasyBC Android SyncCryptoTest.decryptsWebCryptoVector and live web crypto.ts",
3
+ "secret": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8",
4
+ "payload": {
5
+ "schemaVersion": 1,
6
+ "exportedAt": "2026-06-21T12:00:00Z",
7
+ "planner": {
8
+ "value": {
9
+ "ageYears": 37
10
+ },
11
+ "updatedAt": "2026-06-21T12:00:00Z"
12
+ },
13
+ "periodRecords": [],
14
+ "deletedPeriodStarts": {},
15
+ "calendarDayLogs": {},
16
+ "voluntaryAbstinenceDates": {},
17
+ "voluntaryAbstinenceUpdatedAt": {},
18
+ "deletedVoluntaryAbstinenceDates": {},
19
+ "ecJournal": {
20
+ "value": false,
21
+ "updatedAt": "1970-01-01T00:00:00.000Z"
22
+ }
23
+ },
24
+ "envelope": {
25
+ "schemaVersion": 1,
26
+ "algorithm": "AES-256-GCM+HKDF-SHA-256",
27
+ "credentialId": "credential",
28
+ "rpId": "keyneom.github.io",
29
+ "prfInput": "AA",
30
+ "kdfSalt": "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8",
31
+ "nonce": "QEFCQ0RFRkdISUpL",
32
+ "ciphertext": "SGk1csrcbFdGshJaXqUdM-SLg9O0ZjtkHuUREJkV5R89VrpDkTmr12IlZ5W6d4Qk4pQ0kVT9XO7F_r4OHtoWNGbjzrdv49y2LhT-uDLjzNu38r-xVoQXGU3HTJdvr6VFk18TbaKAN08gD3wluMP9JH_IKwpGHeAgZyoajp3agwg4bGV-VSw9URAFlHrXtgJKymwNPz_4E4UHbmjcnCK94JngZgqYXnhBueTwX4fTayIrzqXl_JEcGDm6aEcae_FoqhZ1dVUVx5KynVj_JRgPMKOtviGe-LLk7aXbCoRLxSjZDU4nlPQOV2dFkbrwpV6afwsu1IQWwZ-xvnDovfN8eHzVuvdb7JgSIShs62Yy5N-wgCm-BUWxHp5oq0LUFkGB2njyTQjkmSYBiM4eVOYvhBTIRNQZqFMXSEI32-NyCEaLvv63y43OkQ9-kpWKZ7-yDpM-Mcs5ckNk3IKTHTGhl_0DMpZxA5QONtGvDCW4SHr8dKEQ6aDQ",
33
+ "updatedAt": "2026-06-21T12:00:00Z"
34
+ }
35
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "wrongSecret": "4OHi4-Tl5ufo6err7O3u7_Dx8vP09fb3-Pn6-_z9_v8",
3
+ "tamperedEnvelope": {
4
+ "schemaVersion": 1,
5
+ "algorithm": "AES-256-GCM+HKDF-SHA-256",
6
+ "credentialId": "credential",
7
+ "rpId": "keyneom.github.io",
8
+ "prfInput": "AA",
9
+ "kdfSalt": "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8",
10
+ "nonce": "QEFCQ0RFRkdISUpL",
11
+ "ciphertext": "AGk1csrcbFdGshJaXqUdM-SLg9O0ZjtkHuUREJkV5R89VrpDkTmr12IlZ5W6d4Qk4pQ0kVT9XO7F_r4OHtoWNGbjzrdv49y2LhT-uDLjzNu38r-xVoQXGU3HTJdvr6VFk18TbaKAN08gD3wluMP9JH_IKwpGHeAgZyoajp3agwg4bGV-VSw9URAFlHrXtgJKymwNPz_4E4UHbmjcnCK94JngZgqYXnhBueTwX4fTayIrzqXl_JEcGDm6aEcae_FoqhZ1dVUVx5KynVj_JRgPMKOtviGe-LLk7aXbCoRLxSjZDU4nlPQOV2dFkbrwpV6afwsu1IQWwZ-xvnDovfN8eHzVuvdb7JgSIShs62Yy5N-wgCm-BUWxHp5oq0LUFkGB2njyTQjkmSYBiM4eVOYvhBTIRNQZqFMXSEI32-NyCEaLvv63y43OkQ9-kpWKZ7-yDpM-Mcs5ckNk3IKTHTGhl_0DMpZxA5QONtGvDCW4SHr8dKEQ6aDQ",
12
+ "updatedAt": "2026-06-21T12:00:00Z"
13
+ },
14
+ "wrongContextEnvelope": {
15
+ "schemaVersion": 1,
16
+ "algorithm": "AES-256-GCM+HKDF-SHA-256",
17
+ "credentialId": "fixture-credential",
18
+ "rpId": "keyneom.github.io",
19
+ "prfInput": "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8",
20
+ "kdfSalt": "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8",
21
+ "nonce": "QEFCQ0RFRkdISUpL",
22
+ "ciphertext": "BQrSErMr1-99BpL6zSlFWuWBX2E95QI0FzCgOPe1hVzCEAX6AC94BwSXtF8WaFzt-p-NXyqtMCAtSejFY3VpS76Tk5QkOYaWb30zKkIydzJaxPyxsgsRyTVyc02BlSiV4qLxKy8PevEJ9_ZhrZEup93xuZ29GTgwaNPFilZYTBkGrkwxoQKKJ-Dus3QjRPqbD93o_yyi1sU6Gg3TmnoxX5wO9mQyXiPi856uGnCETa-9SHq3HPP4ZiNXoTzC8nUYPRxDtFfT7xd15T1QsK2ej3sdQz9djURZB9t8hX0Yc0TqbRjuqZZvvhGsodPI8vOw8b-UqSJJ3ZyXzV7yWjCVJ4TjpXAshfhDDbsK2ajZqoKEDEe_c9EH2ZsJwoQaOLmRlB-7v4vbhHrFb_soFf31ANGwXK8stBLyPbjYNducqss0L4F5JDAU_j8FcGMhKX9kFy0n7odbalAZtzN41WVm21LRh1ZBvkak9ycDZNHMHueyccjDcwxl_y0vgjfLD_bQycBLFM_GAy3aVM-H2I0JOJPePdxjqAwOpOSP6VjKZzR--4Glnm1nRj64DO09PFQQttMt8yGK5WsSqNHAP0ViAqW_2QgVH_ClFKfFfwGqb6DMfn1QgQ50m0Xf9ICxKhzFiAvaax82mDoUQju21ZnNQ1hKxvy8NUccCJ-hiT0Vl9RZMO5mXMbagtFMzb8nYYJpJ56M0e0SkHOk8XKYnOgDIUOFybfQLAIG1xYA7GjgxIG0CTUau-1PRCuH5SHntDn7dID2EPllxW3wyQRZpMWw98DodPYfXGo4n2gonLqn2VIF-h9cXGCMkjnnZOFTTFzt1i5zmSyF1prXBFHOQRGTfRZsZd5Iox5tsieiFvEzm5C5bU67G2Gn-wBjSJVmASMlSVxY622eHwkT9HlMnNyZq2fCAcrC-DwQjDx_wGdi_qxRirNIUM5qvoD655R66r7jFbhn6y9LrPrTgrwR1i2c51s5JdtC_JwhFA3nCz816sfK7oGpLq5BLmeVvrPWhiyjDFGByY79_uT63hOekL59uDl7Me_-xauWwbLv",
23
+ "updatedAt": "2026-06-21T00:00:00.000Z"
24
+ },
25
+ "malformedEnvelope": {
26
+ "schemaVersion": 1,
27
+ "algorithm": "AES-256-GCM+HKDF-SHA-256",
28
+ "credentialId": "fixture-credential"
29
+ },
30
+ "decompressionErrorEnvelope": {
31
+ "schemaVersion": 1,
32
+ "algorithm": "AES-256-GCM+HKDF-SHA-256",
33
+ "compression": "gzip",
34
+ "credentialId": "fixture-credential",
35
+ "rpId": "keyneom.github.io",
36
+ "prfInput": "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8",
37
+ "kdfSalt": "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8",
38
+ "nonce": "QEFCQ0RFRkdISUpL",
39
+ "ciphertext": "Uj4yecfXdV9zthRMU-oDfb_TwYW0Zj8rGPkVAPgItAVxC_5RxjT8myZndrL_N9t1v4DvXIgzQ1qpRWd5TXfpZKc",
40
+ "updatedAt": "2026-06-29T00:00:00.000Z"
41
+ }
42
+ }
@@ -0,0 +1,73 @@
1
+ {
2
+ "provenance": "Generated from the uncommitted live Family Chores sync implementation",
3
+ "secret": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8",
4
+ "payload": {
5
+ "schemaVersion": 1,
6
+ "exportedAt": "2026-06-21T00:00:00.000Z",
7
+ "state": {
8
+ "children": [],
9
+ "tasks": [],
10
+ "taskInstances": [],
11
+ "completedTasks": {},
12
+ "timers": {},
13
+ "timedCompletions": [],
14
+ "actionLog": [],
15
+ "parentSettings": {
16
+ "approvals": {
17
+ "task": false,
18
+ "reward": false
19
+ },
20
+ "timedAutoApproveDefault": false,
21
+ "pins": [],
22
+ "childDisplayOrder": [],
23
+ "onboardingCompleted": false,
24
+ "voiceAnnouncements": false
25
+ }
26
+ },
27
+ "metadata": {
28
+ "schemaVersion": 1,
29
+ "collections": {
30
+ "children": {
31
+ "updatedAt": {},
32
+ "deletedAt": {}
33
+ },
34
+ "tasks": {
35
+ "updatedAt": {},
36
+ "deletedAt": {}
37
+ },
38
+ "taskInstances": {
39
+ "updatedAt": {},
40
+ "deletedAt": {}
41
+ },
42
+ "completedTasks": {
43
+ "updatedAt": {},
44
+ "deletedAt": {}
45
+ },
46
+ "timers": {
47
+ "updatedAt": {},
48
+ "deletedAt": {}
49
+ },
50
+ "timedCompletions": {
51
+ "updatedAt": {},
52
+ "deletedAt": {}
53
+ },
54
+ "actionLog": {
55
+ "updatedAt": {},
56
+ "deletedAt": {}
57
+ }
58
+ },
59
+ "parentSettingsUpdatedAt": "1970-01-01T00:00:00.000Z"
60
+ }
61
+ },
62
+ "envelope": {
63
+ "schemaVersion": 1,
64
+ "algorithm": "AES-256-GCM+HKDF-SHA-256",
65
+ "credentialId": "fixture-credential",
66
+ "rpId": "keyneom.github.io",
67
+ "prfInput": "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8",
68
+ "kdfSalt": "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8",
69
+ "nonce": "QEFCQ0RFRkdISUpL",
70
+ "ciphertext": "BQrSErMr1-99BpL6zSlFWuWBX2E95QI0FzCgOPe1hVzCEAX6AC94BwSXtF8WaFzt-p-NXyqtMCAtSejFY3VpS76Tk5QkOYaWb30zKkIydzJaxPyxsgsRyTVyc02BlSiV4qLxKy8PevEJ9_ZhrZEup93xuZ29GTgwaNPFilZYTBkGrkwxoQKKJ-Dus3QjRPqbD93o_yyi1sU6Gg3TmnoxX5wO9mQyXiPi856uGnCETa-9SHq3HPP4ZiNXoTzC8nUYPRxDtFfT7xd15T1QsK2ej3sdQz9djURZB9t8hX0Yc0TqbRjuqZZvvhGsodPI8vOw8b-UqSJJ3ZyXzV7yWjCVJ4TjpXAshfhDDbsK2ajZqoKEDEe_c9EH2ZsJwoQaOLmRlB-7v4vbhHrFb_soFf31ANGwXK8stBLyPbjYNducqss0L4F5JDAU_j8FcGMhKX9kFy0n7odbalAZtzN41WVm21LRh1ZBvkak9ycDZNHMHueyccjDcwxl_y0vgjfLD_bQycBLFM_GAy3aVM-H2I0JOJPePdxjqAwOpOSP6VjKZzR--4Glnm1nRj64DO09PFQQttMt8yGK5WsSqNHAP0ViAqW_2QgVH_ClFKfFfwGqb6DMfn1QgQ50m0Xf9ICxKhzFiAvaax82mDoUQju21ZnNQ1hKxvy8NUccCJ-hiT0Vl9RZMO5mXMbagtFMzb8nYYJpJ56M0e0SkHOk8XKYnOgDIUOFybfQLAIG1xYA7GjgxIG0CTUau-1PRCuH5SHntDn7dID2EPllxW3wyQRZpMWw98DodPYfXGo4n2gonLqn2VIF-h9cXGCMkjnnZOFTTFzt1i5zmSyF1prXBFHOQRGTfRZsZd5Iox5tsieiFvEzm5C5bU67G2Gn-wBjSJVmASMlSVxY622eHwkT9HlMnNyZq2fCAcrC-DwQjDx_wGdi_qxRirNIUM5qvoD655R66r7jFbhn6y9LrPrTgrwR1i2c51s5JdtC_JwhFA3nCz816sfK7oGpLq5BLmeVvrPWhiyjDFGByY79_uT63hOekL59uDl7Me_-xauWwbLv",
71
+ "updatedAt": "2026-06-21T00:00:00.000Z"
72
+ }
73
+ }