@marcoappio/marco-config 3.0.1 → 3.0.3

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.
@@ -106,7 +106,7 @@ export declare const appwriteFunctions: {
106
106
  responseSchema: v.StrictObjectSchema<{
107
107
  readonly commands: v.ArraySchema<v.StrictObjectSchema<{
108
108
  readonly accountId: v.NonOptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>, v.MaxLengthAction<string, number, undefined>, v.BrandAction<string, "AccountId">]>, undefined>;
109
- readonly commandId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.UuidAction<string, undefined>, v.BrandAction<string, "CommandId">]>;
109
+ readonly commandId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 36, undefined>, v.RegexAction<string, undefined>]>;
110
110
  }, undefined>, undefined>;
111
111
  readonly failedAccountIds: v.ArraySchema<v.NonOptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>, v.MaxLengthAction<string, number, undefined>, v.BrandAction<string, "AccountId">]>, undefined>, undefined>;
112
112
  }, undefined>;
@@ -534,6 +534,7 @@ export declare const appwriteFunctions: {
534
534
  method: "POST";
535
535
  path: "/polls/run";
536
536
  requestSchema: v.StrictObjectSchema<{
537
+ readonly scheduledFor: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, undefined>, v.CheckAction<string, undefined>]>;
537
538
  readonly shardId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 36, undefined>, v.RegexAction<string, undefined>]>;
538
539
  }, undefined>;
539
540
  responseSchema: v.StrictObjectSchema<{
@@ -1 +1 @@
1
- {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../src/appwrite/functions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAS5B,KAAK,uBAAuB,GAAG,eAAe,GAAG,UAAU,GAAG,SAAS,CAAA;AA4KvE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWpB,CAAA;AAEV,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iBAAiB,CAAC,WAAW,CAAC,CAAA;AACvF,YAAY,EAAE,uBAAuB,EAAE,CAAA;AACvC,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,QAAQ,CAAA;AACnD,MAAM,MAAM,yBAAyB,CAAC,SAAS,SAAS,oBAAoB,IAAI,SAAS,SAAS,oBAAoB,GAClH,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,GACrD,KAAK,CAAA;AACT,MAAM,MAAM,qBAAqB,CAC/B,SAAS,SAAS,oBAAoB,EACtC,MAAM,SAAS,yBAAyB,CAAC,SAAS,CAAC,IACjD,SAAS,SAAS,oBAAoB,GACtC,MAAM,SAAS,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,GAClE,CAAC,OAAO,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GACvD,KAAK,GACP,KAAK,CAAA;AACT,MAAM,MAAM,uBAAuB,CACjC,SAAS,SAAS,oBAAoB,EACtC,MAAM,SAAS,yBAAyB,CAAC,SAAS,CAAC,IACjD,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS;IAAE,aAAa,EAAE,MAAM,OAAO,SAAS,CAAC,CAAC,aAAa,CAAA;CAAE,GACzG,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,GACtB,KAAK,CAAA;AACT,MAAM,MAAM,wBAAwB,CAClC,SAAS,SAAS,oBAAoB,EACtC,MAAM,SAAS,yBAAyB,CAAC,SAAS,CAAC,IACjD,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS;IAAE,cAAc,EAAE,MAAM,OAAO,SAAS,CAAC,CAAC,aAAa,CAAA;CAAE,GAC1G,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,GACtB,KAAK,CAAA"}
1
+ {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../src/appwrite/functions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAA;AAS5B,KAAK,uBAAuB,GAAG,eAAe,GAAG,UAAU,GAAG,SAAS,CAAA;AAuLvE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWpB,CAAA;AAEV,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,iBAAiB,CAAC,WAAW,CAAC,CAAA;AACvF,YAAY,EAAE,uBAAuB,EAAE,CAAA;AACvC,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,QAAQ,CAAA;AACnD,MAAM,MAAM,yBAAyB,CAAC,SAAS,SAAS,oBAAoB,IAAI,SAAS,SAAS,oBAAoB,GAClH,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,GACrD,KAAK,CAAA;AACT,MAAM,MAAM,qBAAqB,CAC/B,SAAS,SAAS,oBAAoB,EACtC,MAAM,SAAS,yBAAyB,CAAC,SAAS,CAAC,IACjD,SAAS,SAAS,oBAAoB,GACtC,MAAM,SAAS,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,GAClE,CAAC,OAAO,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GACvD,KAAK,GACP,KAAK,CAAA;AACT,MAAM,MAAM,uBAAuB,CACjC,SAAS,SAAS,oBAAoB,EACtC,MAAM,SAAS,yBAAyB,CAAC,SAAS,CAAC,IACjD,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS;IAAE,aAAa,EAAE,MAAM,OAAO,SAAS,CAAC,CAAC,aAAa,CAAA;CAAE,GACzG,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,GACtB,KAAK,CAAA;AACT,MAAM,MAAM,wBAAwB,CAClC,SAAS,SAAS,oBAAoB,EACtC,MAAM,SAAS,yBAAyB,CAAC,SAAS,CAAC,IACjD,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS;IAAE,cAAc,EAAE,MAAM,OAAO,SAAS,CAAC,CAAC,aAAa,CAAA;CAAE,GAC1G,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,GACtB,KAAK,CAAA"}
@@ -48,6 +48,10 @@ const connectionResultSchema = v.strictObject({
48
48
  });
49
49
  const completedSchema = v.strictObject({ state: v.literal('COMPLETED') });
50
50
  const emptySchema = v.strictObject({});
51
+ const timestampSchema = v.pipe(v.string(), v.isoTimestamp(), v.check(timestamp => {
52
+ const milliseconds = Date.parse(timestamp);
53
+ return Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === timestamp;
54
+ }));
51
55
  const createRoute = (route) => ({
52
56
  ...route,
53
57
  errorSchema: functionErrorSchema,
@@ -85,7 +89,7 @@ const apiRoutes = {
85
89
  responseSchema: v.strictObject({
86
90
  commands: v.array(v.strictObject({
87
91
  accountId: id.accountId.required(),
88
- commandId: appwriteCommands.idSchema,
92
+ commandId: appwriteRowIdSchema,
89
93
  })),
90
94
  failedAccountIds: v.array(id.accountId.required()),
91
95
  }),
@@ -137,7 +141,10 @@ const workerRoutes = {
137
141
  context: 'internal',
138
142
  method: 'POST',
139
143
  path: '/polls/run',
140
- requestSchema: v.strictObject({ shardId: appwriteRowIdSchema }),
144
+ requestSchema: v.strictObject({
145
+ scheduledFor: timestampSchema,
146
+ shardId: appwriteRowIdSchema,
147
+ }),
141
148
  responseSchema: completedSchema,
142
149
  }),
143
150
  supervisor: createRoute({
@@ -68,7 +68,7 @@ const routeFixtures = [
68
68
  name: 'account poll',
69
69
  request: {},
70
70
  response: {
71
- commands: [{ accountId: 'test-account-id-1', commandId: '0197f3d4-1b22-7abc-8def-123456789abc' }],
71
+ commands: [{ accountId: 'test-account-id-1', commandId: 'sync_0123456789abcdef0123456789ab' }],
72
72
  failedAccountIds: ['test-account-id-2'],
73
73
  },
74
74
  route: () => appwriteFunctions.api.routes.accountsPoll,
@@ -105,7 +105,7 @@ const routeFixtures = [
105
105
  },
106
106
  {
107
107
  name: 'poll runner',
108
- request: { shardId: 'test-poll-shard-id-1' },
108
+ request: { scheduledFor: '2026-07-23T12:00:30.000Z', shardId: 'test-poll-shard-id-1' },
109
109
  response: { state: 'COMPLETED' },
110
110
  route: () => appwriteFunctions.worker.routes.pollsRun,
111
111
  },
@@ -166,13 +166,60 @@ describe('appwriteFunctions', () => {
166
166
  expect(v.safeParse(requestSchema, { accountId: 'account_1' }).success).toBe(false);
167
167
  expect(v.safeParse(requestSchema, { accountIds: ['account_1'] }).success).toBe(false);
168
168
  });
169
+ for (const { description, value } of [
170
+ { description: 'empty', value: '' },
171
+ { description: 'overlong', value: 'a'.repeat(37) },
172
+ { description: 'illegal', value: 'test/command/id/1' },
173
+ ]) {
174
+ it(`rejects an ${description} manual-poll command ID`, () => {
175
+ expect(v.safeParse(appwriteFunctions.api.routes.accountsPoll.responseSchema, {
176
+ commands: [{ accountId: 'test-account-id-1', commandId: value }],
177
+ failedAccountIds: [],
178
+ }).success).toBe(false);
179
+ });
180
+ }
169
181
  const workerShardRoutes = [
170
- { description: 'poll', requestSchema: appwriteFunctions.worker.routes.pollsRun.requestSchema },
171
- { description: 'watcher', requestSchema: appwriteFunctions.worker.routes.watchersRun.requestSchema },
182
+ {
183
+ description: 'poll',
184
+ request: { scheduledFor: '2026-07-23T12:00:30.000Z', shardId: 'test invalid shard id' },
185
+ requestSchema: appwriteFunctions.worker.routes.pollsRun.requestSchema,
186
+ },
187
+ {
188
+ description: 'watcher',
189
+ request: { shardId: 'test invalid shard id' },
190
+ requestSchema: appwriteFunctions.worker.routes.watchersRun.requestSchema,
191
+ },
172
192
  ];
173
- for (const { description, requestSchema } of workerShardRoutes) {
193
+ for (const { description, request, requestSchema } of workerShardRoutes) {
174
194
  it(`rejects a malformed ${description} shard ID`, () => {
175
- expect(v.safeParse(requestSchema, { shardId: 'test invalid shard id' }).success).toBe(false);
195
+ expect(v.safeParse(requestSchema, request).success).toBe(false);
196
+ });
197
+ }
198
+ for (const { description, request } of [
199
+ { description: 'a missing scheduled slot', request: { shardId: 'test-poll-shard-id-1' } },
200
+ {
201
+ description: 'a malformed scheduled slot',
202
+ request: { scheduledFor: '2026-07-23 12:00:30', shardId: 'test-poll-shard-id-1' },
203
+ },
204
+ {
205
+ description: 'a calendar-impossible scheduled slot',
206
+ request: { scheduledFor: '2026-06-31T12:00:30.000Z', shardId: 'test-poll-shard-id-1' },
207
+ },
208
+ {
209
+ description: 'a non-canonical scheduled slot',
210
+ request: { scheduledFor: '2026-07-23T12:00:30.000+00:00', shardId: 'test-poll-shard-id-1' },
211
+ },
212
+ {
213
+ description: 'an extra field',
214
+ request: {
215
+ scheduledFor: '2026-07-23T12:00:30.000Z',
216
+ shardId: 'test-poll-shard-id-1',
217
+ unexpected: true,
218
+ },
219
+ },
220
+ ]) {
221
+ it(`rejects a poll request with ${description}`, () => {
222
+ expect(v.safeParse(appwriteFunctions.worker.routes.pollsRun.requestSchema, request).success).toBe(false);
176
223
  });
177
224
  }
178
225
  it('redacts credentials from connection responses and compact errors', () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marcoappio/marco-config",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "author": "team@marcoapp.io",
5
5
  "main": "dist/index.js",
6
6
  "repository": "git@github.com:marcoappio/marco-config.git",