@project-ajax/sdk 0.0.56 → 0.0.59

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.
@@ -19,11 +19,33 @@ export type SyncedObject<PK extends string, S extends PropertySchema<PK>> = {
19
19
  */
20
20
  pageContentMarkdown?: string;
21
21
  };
22
+ /**
23
+ * Result returned from the sync execute function.
24
+ */
25
+ export type SyncExecutionResult<PK extends string, Context = unknown> = {
26
+ /**
27
+ * The batch of objects fetched in this execution.
28
+ */
29
+ objects: SyncedObject<PK, PropertySchema<PK>>[];
30
+ /**
31
+ * Indicates whether the sync is complete.
32
+ * - `true`: No more data to fetch, sync is complete
33
+ * - `false`: More data available, will trigger another execution with nextContext
34
+ */
35
+ done: boolean;
36
+ /**
37
+ * Optional context data to pass to the next execution.
38
+ * Required if `done` is `false`, ignored if `done` is `true`.
39
+ * This can be any type of data (cursor, page number, timestamp, etc.).
40
+ * The same data will be provided in the context parameter of the next execution.
41
+ */
42
+ nextContext?: Context;
43
+ };
22
44
  /**
23
45
  * A configuration object that enables synchronization between a data
24
46
  * source and a third-party source.
25
47
  */
26
- export type SyncConfiguration<PK extends string, S extends Schema<PK>> = {
48
+ export type SyncConfiguration<PK extends string, S extends Schema<PK>, Context = unknown> = {
27
49
  /**
28
50
  * The property of the data source that maps to a "primary key" in the
29
51
  * third-party data. This is used to match existing pages to
@@ -34,18 +56,38 @@ export type SyncConfiguration<PK extends string, S extends Schema<PK>> = {
34
56
  * The schema defining the structure of properties in the collection.
35
57
  */
36
58
  schema: S;
59
+ /**
60
+ * Whether to delete pages from the collection that are not returned
61
+ * from any of the sync executions (mark-and-sweep deletion).
62
+ *
63
+ * - `true`: Pages not seen in any execution batch will be deleted
64
+ * - `false` (default): Only upsert pages, never delete
65
+ *
66
+ * @default false
67
+ */
68
+ deleteUnreturnedPages?: boolean;
37
69
  /**
38
70
  * A function that fetches the data to sync from the third-party service.
39
71
  *
40
- * For now, this function must return all of the data to be synced each time
41
- * it's called. The runtime will handle diffing this against the data source
42
- * and creating, updating, and deleting pages as necessary.
72
+ * This function can return all data at once, or implement pagination by:
73
+ * 1. Returning a batch of objects with `done: false` and a `nextContext`
74
+ * 2. The runtime will call execute again with that context data
75
+ * 3. Continue until `done: true` is returned
76
+ *
77
+ * The runtime will handle diffing against the data source and creating,
78
+ * updating, and deleting pages as necessary.
79
+ *
80
+ * @param context - Optional context data from previous execution (undefined on first call)
81
+ * @returns A result containing objects, done status, and optional nextContext
43
82
  */
44
- execute: () => Promise<SyncedObject<PK, PropertySchema<PK>>[]>;
83
+ execute: (context?: Context) => Promise<SyncExecutionResult<PK, Context>>;
45
84
  };
46
- export type SyncHandlerResult<PK extends string> = {
85
+ export type SyncHandlerResult<PK extends string, Context = unknown> = {
47
86
  primaryKeyProperty: PK;
48
87
  objects: SyncedObject<PK, PropertySchema<PK>>[];
88
+ done: boolean;
89
+ nextContext?: Context;
90
+ deleteUnreturnedPages?: boolean;
49
91
  };
50
92
  /**
51
93
  * Creates a special handler for syncing third-party data to a collection.
@@ -54,15 +96,17 @@ export type SyncHandlerResult<PK extends string> = {
54
96
  * @returns A handler function that executes the sync function, and passes data
55
97
  * needed to complete the sync back to the platform.
56
98
  */
57
- export declare function sync<PK extends string, S extends Schema<PK>>(syncConfiguration: SyncConfiguration<PK, S>): {
99
+ export declare function sync<PK extends string, S extends Schema<PK>, Context = unknown>(syncConfiguration: SyncConfiguration<PK, S, Context>): {
58
100
  _tag: string;
59
101
  config: {
102
+ primaryKeyProperty: PK;
60
103
  schema: S;
104
+ deleteUnreturnedPages: boolean | undefined;
61
105
  };
62
- handler(): Promise<{
63
- schema: S;
64
- primaryKeyProperty: PK;
106
+ handler(context?: Context): Promise<{
65
107
  objects: SyncedObject<PK, PropertySchema<PK>>[];
108
+ done: boolean;
109
+ nextContext: Context | undefined;
66
110
  }>;
67
111
  };
68
112
  //# sourceMappingURL=sync.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/capabilities/sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC,SAAS,cAAc,CAAC,EAAE,CAAC,IAAI;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE;SAAG,QAAQ,IAAI,MAAM,CAAC,GAAG,SAAS;KAAE,CAAC;IACjD;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,IAAI;IACxE;;;;OAIG;IACH,kBAAkB,EAAE,EAAE,CAAC;IAEvB;;OAEG;IACH,MAAM,EAAE,CAAC,CAAC;IAEV;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;CAC/D,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,EAAE,SAAS,MAAM,IAAI;IAClD,kBAAkB,EAAE,EAAE,CAAC;IACvB,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;CAChD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,EAC3D,iBAAiB,EAAE,iBAAiB,CAAC,EAAE,EAAE,CAAC,CAAC;;;;;;;;;;EAuB3C"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/capabilities/sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC,SAAS,cAAc,CAAC,EAAE,CAAC,IAAI;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE;SAAG,QAAQ,IAAI,MAAM,CAAC,GAAG,SAAS;KAAE,CAAC;IACjD;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,OAAO,GAAG,OAAO,IAAI;IACvE;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAEhD;;;;OAIG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAC5B,EAAE,SAAS,MAAM,EACjB,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,EACpB,OAAO,GAAG,OAAO,IACd;IACH;;;;OAIG;IACH,kBAAkB,EAAE,EAAE,CAAC;IAEvB;;OAEG;IACH,MAAM,EAAE,CAAC,CAAC;IAEV;;;;;;;;OAQG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;;;;;;;;;;OAaG;IACH,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,mBAAmB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1E,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,OAAO,GAAG,OAAO,IAAI;IACrE,kBAAkB,EAAE,EAAE,CAAC;IACvB,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAChD,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,IAAI,CACnB,EAAE,SAAS,MAAM,EACjB,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,EACpB,OAAO,GAAG,OAAO,EAChB,iBAAiB,EAAE,iBAAiB,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC;;;;;;;sBAQ5B,OAAO;;;;;EAkBhC"}
@@ -3,16 +3,18 @@ function sync(syncConfiguration) {
3
3
  return {
4
4
  _tag: "sync",
5
5
  config: {
6
- schema: syncConfiguration.schema
6
+ primaryKeyProperty: syncConfiguration.primaryKeyProperty,
7
+ schema: syncConfiguration.schema,
8
+ deleteUnreturnedPages: syncConfiguration.deleteUnreturnedPages
7
9
  },
8
- async handler() {
9
- const objects = await syncConfiguration.execute().catch((err) => {
10
+ async handler(context) {
11
+ const executionResult = await syncConfiguration.execute(context).catch((err) => {
10
12
  throw new ExecutionError(err);
11
13
  });
12
14
  const result = {
13
- schema: syncConfiguration.schema,
14
- primaryKeyProperty: syncConfiguration.primaryKeyProperty,
15
- objects
15
+ objects: executionResult.objects,
16
+ done: executionResult.done,
17
+ nextContext: executionResult.nextContext
16
18
  };
17
19
  process.stdout.write(`
18
20
  <output>${JSON.stringify(result)}</output>
@@ -1 +1 @@
1
- {"version":3,"file":"auth.impl.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/auth.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,eAAO,MAAM,KAAK,+GAiChB,CAAC;AAEH,eAAO,MAAM,IAAI,mFAEf,CAAC;AAEH,eAAO,MAAM,MAAM,mFAIjB,CAAC"}
1
+ {"version":3,"file":"auth.impl.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/auth.impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,eAAO,MAAM,KAAK,+GAwChB,CAAC;AAEH,eAAO,MAAM,IAAI,mFAEf,CAAC;AAEH,eAAO,MAAM,MAAM,mFAIjB,CAAC"}
@@ -19,11 +19,15 @@ ${url}
19
19
  }
20
20
  return;
21
21
  }
22
- await this.config.update({
23
- environment,
22
+ const update = {
24
23
  token,
25
24
  workerId: null
26
- });
25
+ };
26
+ console.log("environment", environment);
27
+ if (environment !== "prod") {
28
+ update.environment = environment;
29
+ }
30
+ await this.config.update(update);
27
31
  this.io.writeErr("Successfully logged in!");
28
32
  });
29
33
  const show = buildHandler(function() {
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,YAAY,8CAA+C,CAAC;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,MAAM,WAAW,SAAS;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAM1D;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAEzC,OAAO,GAAE,MAA6D;CAKvE;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,MAAM;;gBAIN,IAAI,EAAE;QACjB,SAAS,EAAE,SAAS,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;KACvB;IAOD,IAAI,OAAO,WAEV;IAED,IAAI,KAAK,kBAER;IAED,IAAI,WAAW,yCAEd;IAED,IAAI,QAAQ,kBAEX;IAED,IAAI,SAAS,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAQlE;IAED;;;;;;;;;OASG;IACG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC;WAc1B,IAAI,CAAC,IAAI,EAAE;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;QAC9B,KAAK,EAAE,WAAW,CAAC;KACnB;CA+FD;AAQD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf,CAoCA"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,YAAY,8CAA+C,CAAC;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,MAAM,WAAW,SAAS;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAM1D;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAEzC,OAAO,GAAE,MAA6D;CAKvE;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,MAAM;;gBAIN,IAAI,EAAE;QACjB,SAAS,EAAE,SAAS,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;KACvB;IAOD,IAAI,OAAO,WAEV;IAED,IAAI,KAAK,kBAER;IAED,IAAI,WAAW,yCAEd;IAED,IAAI,QAAQ,kBAEX;IAED,IAAI,SAAS,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAQlE;IAED;;;;;;;;;OASG;IACG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC;WAc1B,IAAI,CAAC,IAAI,EAAE;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;QAC9B,KAAK,EAAE,WAAW,CAAC;KACnB;CA4FD;AAQD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf,CAoCA"}
@@ -92,9 +92,8 @@ class Config {
92
92
  if (opts.flags["worker-id"]) {
93
93
  partialConfig.workerId = opts.flags["worker-id"];
94
94
  }
95
- partialConfig.baseUrl ??= baseUrlForEnvironment(
96
- partialConfig.environment ?? "prod"
97
- );
95
+ partialConfig.environment ??= "prod";
96
+ partialConfig.baseUrl ??= baseUrlForEnvironment(partialConfig.environment);
98
97
  const environment = partialConfig.environment;
99
98
  if (!environment) {
100
99
  throw new Error("Environment is required");
@@ -134,9 +133,7 @@ class Config {
134
133
  if (isENOENT(error)) {
135
134
  configFile = {
136
135
  token: null,
137
- workerId: null,
138
- environment: "prod",
139
- baseUrl: baseUrlForEnvironment("prod")
136
+ workerId: null
140
137
  };
141
138
  } else {
142
139
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/cli/io.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAe,KAAK,SAAS,EAAkB,MAAM,mBAAmB,CAAC;AAEhF,MAAM,WAAW,aAAa;IAC7B,YAAY,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,EAAE,CAAC;IACrC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CACf;AAED,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,qBAAa,EAAE;;IACd,YAAY,EAAE,OAAO,CAAC;gBAEV,OAAO,EAAE,aAAa;IAIlC;;;;OAIG;IACH,KAAK,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,GAAG,CAAC;IAW7C;;;;OAIG;IACH,QAAQ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAIzD;;;;OAIG;IACH,QAAQ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAIzD;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,YAAY;IAKvC;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,YAAY;IAKvC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IASjE,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;CAkC7D"}
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/cli/io.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAe,KAAK,SAAS,EAAkB,MAAM,mBAAmB,CAAC;AAEhF,MAAM,WAAW,aAAa;IAC7B,YAAY,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,EAAE,CAAC;IACrC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CACf;AAED,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,qBAAa,EAAE;;IACd,YAAY,EAAE,OAAO,CAAC;gBAEV,OAAO,EAAE,aAAa;IAIlC;;;;OAIG;IACH,KAAK,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,GAAG,CAAC;IAW7C;;;;OAIG;IACH,QAAQ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAIzD;;;;OAIG;IACH,QAAQ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAIzD;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,YAAY;IAKvC;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,YAAY;IAKvC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAKjE,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;CAuC7D"}
package/dist/cli/io.js CHANGED
@@ -54,18 +54,19 @@ class IO {
54
54
  this.writeErr(content);
55
55
  }
56
56
  confirm(config) {
57
- if (!process.stdin.isTTY) {
58
- this.writeErr(config.noTTY);
59
- process.exit(1);
60
- }
57
+ this.#ensureTTY(config.noTTY);
61
58
  return prompts.confirm(config).catch(this.#handlePromptExit.bind(this));
62
59
  }
63
60
  input(config) {
61
+ this.#ensureTTY(config.noTTY);
62
+ return prompts.input(config).catch(this.#handlePromptExit.bind(this));
63
+ }
64
+ #ensureTTY(noTTY) {
64
65
  if (!process.stdin.isTTY) {
65
- this.writeErr(config.noTTY);
66
+ this.writeErr(noTTY);
66
67
  process.exit(1);
67
68
  }
68
- return prompts.input(config).catch(this.#handlePromptExit.bind(this));
69
+ return true;
69
70
  }
70
71
  #handlePromptExit(err) {
71
72
  if (err instanceof Error && err.name === "ExitPromptError") {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { emojiIcon, notionIcon } from "./builder.js";
2
2
  export { slashCommand } from "./capabilities/slashCommand.js";
3
+ export type { SyncConfiguration, SyncExecutionResult, SyncedObject, } from "./capabilities/sync.js";
3
4
  export { sync } from "./capabilities/sync.js";
4
5
  export { tool } from "./capabilities/tool.js";
5
6
  export type { Icon, NoticonColor, NoticonName } from "./types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,YAAY,EACX,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@project-ajax/sdk",
3
- "version": "0.0.56",
3
+ "version": "0.0.59",
4
4
  "description": "An SDK for building workers for the Project Ajax platform",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -20,11 +20,40 @@ export type SyncedObject<PK extends string, S extends PropertySchema<PK>> = {
20
20
  pageContentMarkdown?: string;
21
21
  };
22
22
 
23
+ /**
24
+ * Result returned from the sync execute function.
25
+ */
26
+ export type SyncExecutionResult<PK extends string, Context = unknown> = {
27
+ /**
28
+ * The batch of objects fetched in this execution.
29
+ */
30
+ objects: SyncedObject<PK, PropertySchema<PK>>[];
31
+
32
+ /**
33
+ * Indicates whether the sync is complete.
34
+ * - `true`: No more data to fetch, sync is complete
35
+ * - `false`: More data available, will trigger another execution with nextContext
36
+ */
37
+ done: boolean;
38
+
39
+ /**
40
+ * Optional context data to pass to the next execution.
41
+ * Required if `done` is `false`, ignored if `done` is `true`.
42
+ * This can be any type of data (cursor, page number, timestamp, etc.).
43
+ * The same data will be provided in the context parameter of the next execution.
44
+ */
45
+ nextContext?: Context;
46
+ };
47
+
23
48
  /**
24
49
  * A configuration object that enables synchronization between a data
25
50
  * source and a third-party source.
26
51
  */
27
- export type SyncConfiguration<PK extends string, S extends Schema<PK>> = {
52
+ export type SyncConfiguration<
53
+ PK extends string,
54
+ S extends Schema<PK>,
55
+ Context = unknown,
56
+ > = {
28
57
  /**
29
58
  * The property of the data source that maps to a "primary key" in the
30
59
  * third-party data. This is used to match existing pages to
@@ -37,19 +66,40 @@ export type SyncConfiguration<PK extends string, S extends Schema<PK>> = {
37
66
  */
38
67
  schema: S;
39
68
 
69
+ /**
70
+ * Whether to delete pages from the collection that are not returned
71
+ * from any of the sync executions (mark-and-sweep deletion).
72
+ *
73
+ * - `true`: Pages not seen in any execution batch will be deleted
74
+ * - `false` (default): Only upsert pages, never delete
75
+ *
76
+ * @default false
77
+ */
78
+ deleteUnreturnedPages?: boolean;
79
+
40
80
  /**
41
81
  * A function that fetches the data to sync from the third-party service.
42
82
  *
43
- * For now, this function must return all of the data to be synced each time
44
- * it's called. The runtime will handle diffing this against the data source
45
- * and creating, updating, and deleting pages as necessary.
83
+ * This function can return all data at once, or implement pagination by:
84
+ * 1. Returning a batch of objects with `done: false` and a `nextContext`
85
+ * 2. The runtime will call execute again with that context data
86
+ * 3. Continue until `done: true` is returned
87
+ *
88
+ * The runtime will handle diffing against the data source and creating,
89
+ * updating, and deleting pages as necessary.
90
+ *
91
+ * @param context - Optional context data from previous execution (undefined on first call)
92
+ * @returns A result containing objects, done status, and optional nextContext
46
93
  */
47
- execute: () => Promise<SyncedObject<PK, PropertySchema<PK>>[]>;
94
+ execute: (context?: Context) => Promise<SyncExecutionResult<PK, Context>>;
48
95
  };
49
96
 
50
- export type SyncHandlerResult<PK extends string> = {
97
+ export type SyncHandlerResult<PK extends string, Context = unknown> = {
51
98
  primaryKeyProperty: PK;
52
99
  objects: SyncedObject<PK, PropertySchema<PK>>[];
100
+ done: boolean;
101
+ nextContext?: Context;
102
+ deleteUnreturnedPages?: boolean;
53
103
  };
54
104
 
55
105
  /**
@@ -59,23 +109,29 @@ export type SyncHandlerResult<PK extends string> = {
59
109
  * @returns A handler function that executes the sync function, and passes data
60
110
  * needed to complete the sync back to the platform.
61
111
  */
62
- export function sync<PK extends string, S extends Schema<PK>>(
63
- syncConfiguration: SyncConfiguration<PK, S>,
64
- ) {
112
+ export function sync<
113
+ PK extends string,
114
+ S extends Schema<PK>,
115
+ Context = unknown,
116
+ >(syncConfiguration: SyncConfiguration<PK, S, Context>) {
65
117
  return {
66
118
  _tag: "sync",
67
119
  config: {
120
+ primaryKeyProperty: syncConfiguration.primaryKeyProperty,
68
121
  schema: syncConfiguration.schema,
122
+ deleteUnreturnedPages: syncConfiguration.deleteUnreturnedPages,
69
123
  },
70
- async handler() {
71
- const objects = await syncConfiguration.execute().catch((err) => {
72
- throw new ExecutionError(err);
73
- });
124
+ async handler(context?: Context) {
125
+ const executionResult = await syncConfiguration
126
+ .execute(context)
127
+ .catch((err) => {
128
+ throw new ExecutionError(err);
129
+ });
74
130
 
75
131
  const result = {
76
- schema: syncConfiguration.schema,
77
- primaryKeyProperty: syncConfiguration.primaryKeyProperty,
78
- objects,
132
+ objects: executionResult.objects,
133
+ done: executionResult.done,
134
+ nextContext: executionResult.nextContext,
79
135
  };
80
136
 
81
137
  process.stdout.write(`\n<output>${JSON.stringify(result)}</output>\n`);
@@ -125,9 +125,11 @@ describe("login", () => {
125
125
  configFile: {
126
126
  token: null,
127
127
  workerId: null,
128
- environment: "prod",
129
128
  baseUrl: "https://www.notion.so",
130
129
  },
130
+ flags: {
131
+ env: "local",
132
+ },
131
133
  });
132
134
 
133
135
  vi.spyOn(Config, "load").mockResolvedValue(mockConfig);
@@ -142,9 +144,9 @@ describe("login", () => {
142
144
  await login.call(context, baseFlags, testToken);
143
145
 
144
146
  expect(updateSpy).toHaveBeenCalledWith({
145
- environment: "prod",
146
147
  token: testToken,
147
148
  workerId: null,
149
+ environment: "local",
148
150
  });
149
151
  });
150
152
  });
@@ -1,3 +1,4 @@
1
+ import type { ConfigMap } from "../config.js";
1
2
  import type { GlobalFlags } from "../flags.js";
2
3
  import { buildHandler, type HandlerContext } from "../handler.js";
3
4
  import { openNotionUrl } from "../utils/openUrl.js";
@@ -28,11 +29,18 @@ export const login = buildHandler(async function (
28
29
  return;
29
30
  }
30
31
 
31
- await this.config.update({
32
- environment,
32
+ const update: Partial<ConfigMap> = {
33
33
  token,
34
34
  workerId: null,
35
- });
35
+ };
36
+
37
+ console.log("environment", environment);
38
+
39
+ if (environment !== "prod") {
40
+ update.environment = environment;
41
+ }
42
+
43
+ await this.config.update(update);
36
44
 
37
45
  this.io.writeErr("Successfully logged in!");
38
46
  });
package/src/cli/config.ts CHANGED
@@ -141,9 +141,8 @@ export class Config {
141
141
  partialConfig.workerId = opts.flags["worker-id"];
142
142
  }
143
143
 
144
- partialConfig.baseUrl ??= baseUrlForEnvironment(
145
- partialConfig.environment ?? "prod",
146
- );
144
+ partialConfig.environment ??= "prod";
145
+ partialConfig.baseUrl ??= baseUrlForEnvironment(partialConfig.environment);
147
146
 
148
147
  const environment = partialConfig.environment;
149
148
  if (!environment) {
@@ -194,8 +193,6 @@ export class Config {
194
193
  configFile = {
195
194
  token: null,
196
195
  workerId: null,
197
- environment: "prod",
198
- baseUrl: baseUrlForEnvironment("prod"),
199
196
  };
200
197
  } else {
201
198
  throw error;
package/src/cli/io.ts CHANGED
@@ -1,4 +1,6 @@
1
+ // biome-ignore lint/style/noRestrictedImports: This file contains safe wrappers for prompts.
1
2
  import * as prompts from "@inquirer/prompts";
3
+ // biome-ignore lint/style/noRestrictedImports: This is the one allowed location for this import.
2
4
  import { createTable, type TableCell, type TableItem } from "@visulima/tabular";
3
5
 
4
6
  export interface WriterOptions {
@@ -80,21 +82,22 @@ export class IO {
80
82
  }
81
83
 
82
84
  confirm(config: WithSafety<Parameters<typeof prompts.confirm>[0]>) {
83
- if (!process.stdin.isTTY) {
84
- this.writeErr(config.noTTY);
85
- process.exit(1);
86
- }
87
-
85
+ this.#ensureTTY(config.noTTY);
88
86
  return prompts.confirm(config).catch(this.#handlePromptExit.bind(this));
89
87
  }
90
88
 
91
89
  input(config: WithSafety<Parameters<typeof prompts.input>[0]>) {
90
+ this.#ensureTTY(config.noTTY);
91
+ return prompts.input(config).catch(this.#handlePromptExit.bind(this));
92
+ }
93
+
94
+ #ensureTTY(noTTY: string): true | never {
92
95
  if (!process.stdin.isTTY) {
93
- this.writeErr(config.noTTY);
96
+ this.writeErr(noTTY);
94
97
  process.exit(1);
95
98
  }
96
99
 
97
- return prompts.input(config).catch(this.#handlePromptExit.bind(this));
100
+ return true;
98
101
  }
99
102
 
100
103
  #handlePromptExit(err: unknown) {
package/src/index.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  export { emojiIcon, notionIcon } from "./builder.js";
2
2
  export { slashCommand } from "./capabilities/slashCommand.js";
3
+ export type {
4
+ SyncConfiguration,
5
+ SyncExecutionResult,
6
+ SyncedObject,
7
+ } from "./capabilities/sync.js";
3
8
  export { sync } from "./capabilities/sync.js";
4
9
  export { tool } from "./capabilities/tool.js";
5
10
  export type { Icon, NoticonColor, NoticonName } from "./types.js";