@ganju/utils 0.0.21 → 0.0.22

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 (51) hide show
  1. package/dist/data.d.ts +4 -4
  2. package/dist/data.d.ts.map +1 -1
  3. package/dist/data.js +16 -2
  4. package/dist/dataApi.d.ts +32 -2
  5. package/dist/dataApi.d.ts.map +1 -1
  6. package/dist/dataApi.js +11 -1
  7. package/dist/dataCompiler.d.ts +1 -0
  8. package/dist/dataCompiler.d.ts.map +1 -1
  9. package/dist/dataCompiler.js +3 -2
  10. package/dist/dataEngine.d.ts +17 -1
  11. package/dist/dataEngine.d.ts.map +1 -1
  12. package/dist/dataEngine.js +368 -10
  13. package/dist/dataImport.d.ts +3 -0
  14. package/dist/dataImport.d.ts.map +1 -1
  15. package/dist/dataImport.js +12 -2
  16. package/dist/dataRpc.d.ts +9 -1
  17. package/dist/dataRpc.d.ts.map +1 -1
  18. package/dist/dataSheet.d.ts +34 -0
  19. package/dist/dataSheet.d.ts.map +1 -0
  20. package/dist/dataSheet.js +100 -0
  21. package/dist/dataTriggers.d.ts +43 -4
  22. package/dist/dataTriggers.d.ts.map +1 -1
  23. package/dist/dataTriggers.js +401 -19
  24. package/dist/dataTypes.d.ts +23 -0
  25. package/dist/dataTypes.d.ts.map +1 -1
  26. package/dist/dataTypes.js +15 -1
  27. package/dist/index.d.ts +35 -4
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -0
  30. package/dist/localizeDataError.d.ts.map +1 -1
  31. package/dist/localizeDataError.js +45 -1
  32. package/dist/schema.d.ts +33 -4
  33. package/dist/schema.d.ts.map +1 -1
  34. package/dist/schema.js +26 -3
  35. package/dist/untrustedContent.d.ts +7 -0
  36. package/dist/untrustedContent.d.ts.map +1 -1
  37. package/dist/untrustedContent.js +13 -1
  38. package/package.json +1 -1
  39. package/src/data.ts +19 -3
  40. package/src/dataApi.ts +14 -2
  41. package/src/dataCompiler.ts +4 -1
  42. package/src/dataEngine.ts +485 -10
  43. package/src/dataImport.ts +16 -1
  44. package/src/dataRpc.ts +10 -1
  45. package/src/dataSheet.ts +147 -0
  46. package/src/dataTriggers.ts +528 -19
  47. package/src/dataTypes.ts +46 -0
  48. package/src/index.ts +4 -0
  49. package/src/localizeDataError.ts +82 -1
  50. package/src/schema.ts +27 -3
  51. package/src/untrustedContent.ts +15 -0
package/src/data.ts CHANGED
@@ -65,9 +65,12 @@ export {
65
65
  writeReachesCopy,
66
66
  assertActor,
67
67
  assertWritable,
68
+ assertNotSynced,
69
+ syncRows,
70
+ recordSyncFailure,
68
71
  exportRows
69
72
  } from './dataEngine';
70
- export type { SqlRow, SqlRunner } from './dataEngine';
73
+ export type { SqlRow, SqlRunner, SheetSyncArgs } from './dataEngine';
71
74
  export { adviseIndexes, adviceDoubled } from './dataIndexAdvice';
72
75
  export type {
73
76
  IndexAdviceCandidate,
@@ -118,6 +121,7 @@ export {
118
121
  export type { DataToolDefinition, DataAdminAction } from './dataTools';
119
122
  export {
120
123
  DATA_TRIGGER_EVENTS,
124
+ DATA_CHANGE_EVENTS,
121
125
  DATA_TRIGGER_ACTIONS,
122
126
  DATA_MAX_TRIGGERS,
123
127
  DATA_TRIGGER_MAX_DEPTH,
@@ -125,6 +129,12 @@ export {
125
129
  DATA_TRIGGER_MAX_RATE,
126
130
  DATA_OUTBOX_BATCH,
127
131
  DATA_TRIGGER_MAX_MESSAGE_BYTES,
132
+ DATA_TIME_SCAN_MS,
133
+ DATA_TIME_MIN_MINUTES,
134
+ DATA_TIME_MAX_MINUTES,
135
+ DATA_MAX_TIME_TRIGGERS,
136
+ DATA_TIME_EVENTS_PER_SCAN,
137
+ DATA_TIME_EVENTS_PER_DAY,
128
138
  utf8Bytes,
129
139
  conditionMatches,
130
140
  renderTriggerText,
@@ -144,7 +154,11 @@ export {
144
154
  outboxSize,
145
155
  clearOutbox,
146
156
  triggersUsingColumn,
147
- renameColumnInTriggers
157
+ renameColumnInTriggers,
158
+ timeTriggersCountingFrom,
159
+ syncTimeIndexes,
160
+ hasTimeTriggers,
161
+ scanTimeTriggers
148
162
  } from './dataTriggers';
149
163
  export type {
150
164
  DataTrigger,
@@ -155,8 +169,10 @@ export type {
155
169
  DataTriggerEvent,
156
170
  DataTriggerEventMessage,
157
171
  DataTriggerInput,
172
+ DataTriggerSchedule,
158
173
  DataTriggerTemplate,
159
174
  DataTriggerTest,
160
175
  DataTriggerWithSecret,
161
- SavedTrigger
176
+ SavedTrigger,
177
+ TimeScanResult
162
178
  } from './dataTriggers';
package/src/dataApi.ts CHANGED
@@ -27,7 +27,7 @@ export interface DataApiRoute {
27
27
  query?: z.ZodObject;
28
28
  // What a 200/201 answers with, in a sentence.
29
29
  returns: string;
30
- status?: 200 | 201;
30
+ status?: 200 | 201 | 202;
31
31
  // Answers with a file instead of JSON.
32
32
  file?: boolean;
33
33
  }
@@ -179,9 +179,21 @@ export const DATA_API_ROUTES = {
179
179
  path: '/table/:table',
180
180
  tag: 'Tables',
181
181
  summary: 'Rename a table or change its settings',
182
+ description:
183
+ "`source` (`{ uri, sheet?, key }`) keeps the table's rows in step with a spreadsheet or CSV in the project's knowledge, matched by `key`, a unique column: the sheet wins, and row writes to the table are refused until `source` is set back to null. It syncs when the file changes and from `POST …/sync`; `sync` on the table says how the last one went.",
182
184
  body: DATA_TABLE_PATCH,
183
185
  returns: '{ table }'
184
186
  },
187
+ syncTable: {
188
+ method: 'post',
189
+ path: '/table/:table/sync',
190
+ tag: 'Tables',
191
+ summary: 'Sync a table from its sheet now',
192
+ description:
193
+ "Queues a sync of a table that has a `source`: a Google Drive or OneDrive file is fetched again first if it changed. New keys are inserted, rows that differ updated (actor `system:sheet-sync`, so triggers fire), rows whose key is gone deleted. A sheet that doesn't fit (a missing key column, a repeated key, a value a column won't take) changes nothing; the table's `sync` says why.",
194
+ returns: '{ queued: true }',
195
+ status: 202
196
+ },
185
197
  dropTable: {
186
198
  method: 'delete',
187
199
  path: '/table/:table',
@@ -347,7 +359,7 @@ export const DATA_API_ROUTES = {
347
359
  tag: 'Triggers',
348
360
  summary: 'Save a trigger',
349
361
  description:
350
- 'Runs one action when rows of `table` are inserted, updated or deleted, and `when` holds: `{ "status": { "changedTo": "READY" } }` fires on the transition only; `changedFrom`, `changed: true` and `equals` test a column too, and `all` / `any` combine them. The action is one of `function` (a function of this project, given `{ event, table, row, previous, actor, eventId, triggerId }`), `webhook` (an https URL, sent a POST signed in `x-ganju-signature`), `chat` (`{ channelId, chatId, text }`), `email` (`{ to, subject, text }`) or `customer` (`{ text, template? }`, to the row\'s customer on a customer-scoped table). Texts take `{{field}}` from the row, inserted as plain text. Saving under an existing name replaces it, unless `replace` is false; with no `name`, it always creates a new trigger, named from the table, event and action and numbered past those taken. Left out, `enabled` keeps a saved trigger on or off as it was. A new webhook answers with its signing `secret`, shown this once. An `email` goes to the organization\'s members; any other address is sent a link to confirm first, and those still waiting come back as `confirming`. Delivery is at least once: every event carries an `eventId`.',
362
+ 'Runs one action when rows of `table` are inserted, updated or deleted, and `when` holds: `{ "status": { "changedTo": "READY" } }` fires on the transition only; `changedFrom`, `changed: true` and `equals` test a column too, and `all` / `any` combine them. With `"on": "time"` it fires instead once a row comes due, with nothing written: `after` is `{ column, minutes }`, the column `created_at`, `updated_at` or a date or datetime column (a date counts from midnight in the database\'s time zone) and `minutes` 5 to 43,200, negative on a date or datetime for before it. Its `when` tests `equals` only, read when the row comes due; rows already due when it is saved don\'t fire, and each row fires once per due time (an `updated_at` trigger again after the next change). Due rows are looked for every 5 minutes, up to 100 events per trigger per scan; a database holds up to 10 time triggers, and the database\'s time triggers share 2,000 events a day (UTC): past that, each time trigger with another row due that day is turned off and the organization\'s admins are emailed. A time trigger is also turned off when its runs are paused (the plan no longer includes Data, or the month\'s trigger runs reached the plan\'s limit). The action is one of `function` (a function of this project, given `{ event, table, row, previous, actor, eventId, triggerId, dueAt? }`), `webhook` (an https URL, sent a POST signed in `x-ganju-signature`), `chat` (`{ channelId, chatId, text }`), `email` (`{ to, subject, text }`) or `customer` (`{ text, template? }`, to the row\'s customer on a customer-scoped table). Texts take `{{field}}` from the row, inserted as plain text. Saving under an existing name replaces it, unless `replace` is false; with no `name`, it always creates a new trigger, named from the table, event and action and numbered past those taken. Left out, `enabled` keeps a saved trigger on or off as it was. A new webhook answers with its signing `secret`, shown this once. An `email` goes to the organization\'s members; any other address is sent a link to confirm first, and those still waiting come back as `confirming`. Delivery is at least once: every event carries an `eventId`.',
351
363
  body: DATA_TRIGGER_INPUT,
352
364
  returns: '{ trigger, secret?, confirming? }',
353
365
  status: 201
@@ -194,7 +194,10 @@ const LOCAL_DATETIME =
194
194
  // "2026-10-21T15:00:00" with no offset, read as a wall-clock time in
195
195
  // `timeZone` (UTC without one). `new Date()` would read it in the server's
196
196
  // zone: UTC on Workers, the developer's own zone on a laptop.
197
- const localDatetime = (value: string, timeZone?: string): Date | null => {
197
+ export const localDatetime = (
198
+ value: string,
199
+ timeZone?: string
200
+ ): Date | null => {
198
201
  const m = LOCAL_DATETIME.exec(value.trim());
199
202
  if (!m) return null;
200
203
  const [year, month, day, hour, minute, second] = m