@dinoxx/dinox-cli 1.1.0 → 2.0.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 (111) hide show
  1. package/README.md +48 -4
  2. package/dist/cli.js +4 -0
  3. package/dist/commands/auth/index.js +1 -2
  4. package/dist/commands/boxes/index.js +37 -13
  5. package/dist/commands/boxes/operations.d.ts +3 -3
  6. package/dist/commands/boxes/operations.js +51 -28
  7. package/dist/commands/info/index.js +30 -5
  8. package/dist/commands/meta/repo.js +2 -1
  9. package/dist/commands/notes/actions.js +20 -37
  10. package/dist/commands/notes/bulk.d.ts +2 -2
  11. package/dist/commands/notes/bulk.js +3 -18
  12. package/dist/commands/notes/contentPatch.d.ts +5 -1
  13. package/dist/commands/notes/contentPatch.js +12 -1
  14. package/dist/commands/notes/contentPatchCommand.d.ts +3 -0
  15. package/dist/commands/notes/contentPatchCommand.js +29 -8
  16. package/dist/commands/notes/descriptors.js +19 -16
  17. package/dist/commands/notes/export.js +3 -0
  18. package/dist/commands/notes/repo.d.ts +9 -0
  19. package/dist/commands/notes/repo.js +65 -15
  20. package/dist/commands/notes/searchOutput.d.ts +2 -1
  21. package/dist/commands/notes/searchOutput.js +2 -1
  22. package/dist/commands/notes/searchSql.js +9 -3
  23. package/dist/commands/prompt/index.d.ts +1 -0
  24. package/dist/commands/prompt/index.js +26 -11
  25. package/dist/commands/runtime.js +17 -6
  26. package/dist/commands/savedViews/index.d.ts +7 -0
  27. package/dist/commands/savedViews/index.js +458 -0
  28. package/dist/commands/savedViews/model.d.ts +87 -0
  29. package/dist/commands/savedViews/model.js +306 -0
  30. package/dist/commands/savedViews/repo.d.ts +123 -0
  31. package/dist/commands/savedViews/repo.js +512 -0
  32. package/dist/commands/savedViews/semantics.d.ts +46 -0
  33. package/dist/commands/savedViews/semantics.js +738 -0
  34. package/dist/commands/schema/renderSkills.d.ts +2 -0
  35. package/dist/commands/schema/renderSkills.js +69 -10
  36. package/dist/commands/schema/spec.js +4 -0
  37. package/dist/commands/skills/index.d.ts +54 -0
  38. package/dist/commands/skills/index.js +468 -0
  39. package/dist/commands/storage/index.js +2 -2
  40. package/dist/commands/sync.d.ts +23 -1
  41. package/dist/commands/sync.js +100 -58
  42. package/dist/commands/tags/index.js +30 -11
  43. package/dist/commands/tags/operations.d.ts +3 -3
  44. package/dist/commands/tags/operations.js +45 -20
  45. package/dist/commands/templates/model.d.ts +50 -0
  46. package/dist/commands/templates/model.js +239 -0
  47. package/dist/commands/todo/index.js +3 -3
  48. package/dist/commands/update.d.ts +1 -0
  49. package/dist/commands/update.js +46 -9
  50. package/dist/commands/writeConfirmation.d.ts +13 -0
  51. package/dist/commands/writeConfirmation.js +54 -0
  52. package/dist/config/resolve.js +5 -10
  53. package/dist/config/types.d.ts +3 -6
  54. package/dist/constants/links.d.ts +18 -1
  55. package/dist/constants/links.js +26 -1
  56. package/dist/daemon/client.d.ts +2 -2
  57. package/dist/daemon/client.js +106 -52
  58. package/dist/daemon/index.d.ts +5 -3
  59. package/dist/daemon/index.js +28 -5
  60. package/dist/daemon/lifecycle.d.ts +10 -3
  61. package/dist/daemon/lifecycle.js +54 -11
  62. package/dist/daemon/pid.d.ts +1 -1
  63. package/dist/daemon/pid.js +6 -3
  64. package/dist/dinox.js +9 -1
  65. package/dist/powersync/exclusiveRuntime.d.ts +2 -0
  66. package/dist/powersync/exclusiveRuntime.js +28 -4
  67. package/dist/powersync/runtime.d.ts +4 -2
  68. package/dist/powersync/runtime.js +43 -5
  69. package/dist/powersync/schema/content.d.ts +1 -78
  70. package/dist/powersync/schema/content.js +1 -78
  71. package/dist/powersync/schema/electronCanonical.d.ts +1561 -0
  72. package/dist/powersync/schema/electronCanonical.js +1154 -0
  73. package/dist/powersync/schema/index.d.ts +573 -129
  74. package/dist/powersync/schema/index.js +3 -32
  75. package/dist/powersync/schema/local.d.ts +1 -56
  76. package/dist/powersync/schema/local.js +1 -60
  77. package/dist/powersync/schema/note.d.ts +1 -35
  78. package/dist/powersync/schema/note.js +1 -35
  79. package/dist/powersync/schema/notesExtras.d.ts +1 -62
  80. package/dist/powersync/schema/notesExtras.js +1 -71
  81. package/dist/powersync/schema/projects.d.ts +1 -104
  82. package/dist/powersync/schema/projects.js +1 -104
  83. package/dist/powersync/schema/savedViews.d.ts +1 -0
  84. package/dist/powersync/schema/savedViews.js +1 -0
  85. package/dist/powersync/schema/storage.d.ts +1 -24
  86. package/dist/powersync/schema/storage.js +1 -24
  87. package/dist/powersync/schema/tags.d.ts +1 -37
  88. package/dist/powersync/schema/tags.js +1 -37
  89. package/dist/powersync/syncGate.d.ts +22 -3
  90. package/dist/powersync/syncGate.js +4 -1
  91. package/dist/powersync/syncPass.d.ts +2 -0
  92. package/dist/powersync/syncPass.js +15 -4
  93. package/dist/powersync/tokenIndex.d.ts +2 -0
  94. package/dist/powersync/tokenIndex.js +60 -18
  95. package/dist/powersync/uploader.d.ts +16 -2
  96. package/dist/powersync/uploader.js +152 -158
  97. package/dist/skills/check.d.ts +1 -0
  98. package/dist/skills/check.js +538 -70
  99. package/dist/skills/retired.d.ts +60 -0
  100. package/dist/skills/retired.js +58 -0
  101. package/dist/utils/deadline.d.ts +8 -0
  102. package/dist/utils/deadline.js +31 -0
  103. package/dist/utils/dryRun.d.ts +20 -1
  104. package/dist/utils/dryRun.js +22 -3
  105. package/dist/utils/errors.d.ts +2 -0
  106. package/dist/utils/errors.js +5 -3
  107. package/dist/utils/processExit.d.ts +1 -0
  108. package/dist/utils/processExit.js +33 -0
  109. package/dist/utils/updateNotice.d.ts +1 -0
  110. package/dist/utils/updateNotice.js +1 -1
  111. package/package.json +10 -5
@@ -1,24 +1 @@
1
- import { column, Table } from '@powersync/common';
2
- export const c_storage = new Table({
3
- id: column.text,
4
- user_id: column.text,
5
- alias_name: column.text,
6
- protocol: column.text,
7
- provider: column.text,
8
- is_active: column.integer,
9
- sort_rank: column.integer,
10
- endpoint: column.text,
11
- bucket: column.text,
12
- region: column.text,
13
- access_key_id: column.text,
14
- secret_access_key: column.text,
15
- force_path_style: column.integer,
16
- path_prefix: column.text,
17
- custom_domain: column.text,
18
- legacy_domains: column.text,
19
- is_private: column.integer,
20
- extra_config: column.text,
21
- created_at: column.text,
22
- updated_at: column.text,
23
- deleted_at: column.text,
24
- });
1
+ export { c_storage } from './electronCanonical.js';
@@ -1,37 +1 @@
1
- import { Table } from '@powersync/common';
2
- export declare const c_tag: Table<{
3
- id: import("@powersync/common").BaseColumnType<string | null>;
4
- tags: import("@powersync/common").BaseColumnType<string | null>;
5
- insert_at: import("@powersync/common").BaseColumnType<string | null>;
6
- extra_data: import("@powersync/common").BaseColumnType<string | null>;
7
- update_at: import("@powersync/common").BaseColumnType<string | null>;
8
- user_id: import("@powersync/common").BaseColumnType<string | null>;
9
- is_del: import("@powersync/common").BaseColumnType<number | null>;
10
- favorite_tags: import("@powersync/common").BaseColumnType<string | null>;
11
- }>;
12
- export declare const c_tag_node: Table<{
13
- id: import("@powersync/common").BaseColumnType<string | null>;
14
- user_id: import("@powersync/common").BaseColumnType<string | null>;
15
- emoji: import("@powersync/common").BaseColumnType<string | null>;
16
- full_path: import("@powersync/common").BaseColumnType<string | null>;
17
- path_key: import("@powersync/common").BaseColumnType<string | null>;
18
- parent_id: import("@powersync/common").BaseColumnType<string | null>;
19
- depth: import("@powersync/common").BaseColumnType<number | null>;
20
- is_actual: import("@powersync/common").BaseColumnType<number | null>;
21
- is_del: import("@powersync/common").BaseColumnType<number | null>;
22
- created_at: import("@powersync/common").BaseColumnType<string | null>;
23
- updated_at: import("@powersync/common").BaseColumnType<string | null>;
24
- meta: import("@powersync/common").BaseColumnType<string | null>;
25
- }>;
26
- export declare const c_tag_preference: Table<{
27
- id: import("@powersync/common").BaseColumnType<string | null>;
28
- user_id: import("@powersync/common").BaseColumnType<string | null>;
29
- tag_id: import("@powersync/common").BaseColumnType<string | null>;
30
- is_favorite: import("@powersync/common").BaseColumnType<number | null>;
31
- is_expanded: import("@powersync/common").BaseColumnType<number | null>;
32
- pinned_at: import("@powersync/common").BaseColumnType<string | null>;
33
- sort_rank: import("@powersync/common").BaseColumnType<number | null>;
34
- pinned_rank: import("@powersync/common").BaseColumnType<number | null>;
35
- created_at: import("@powersync/common").BaseColumnType<string | null>;
36
- updated_at: import("@powersync/common").BaseColumnType<string | null>;
37
- }>;
1
+ export { c_tag_node, c_tag_preference } from './electronCanonical.js';
@@ -1,37 +1 @@
1
- import { column, Table } from '@powersync/common';
2
- export const c_tag = new Table({
3
- id: column.text,
4
- tags: column.text,
5
- insert_at: column.text,
6
- extra_data: column.text,
7
- update_at: column.text,
8
- user_id: column.text,
9
- is_del: column.integer,
10
- favorite_tags: column.text,
11
- });
12
- export const c_tag_node = new Table({
13
- id: column.text,
14
- user_id: column.text,
15
- emoji: column.text,
16
- full_path: column.text,
17
- path_key: column.text,
18
- parent_id: column.text,
19
- depth: column.integer,
20
- is_actual: column.integer,
21
- is_del: column.integer,
22
- created_at: column.text,
23
- updated_at: column.text,
24
- meta: column.text,
25
- });
26
- export const c_tag_preference = new Table({
27
- id: column.text,
28
- user_id: column.text,
29
- tag_id: column.text,
30
- is_favorite: column.integer,
31
- is_expanded: column.integer,
32
- pinned_at: column.text,
33
- sort_rank: column.integer,
34
- pinned_rank: column.integer,
35
- created_at: column.text,
36
- updated_at: column.text,
37
- });
1
+ export { c_tag_node, c_tag_preference } from './electronCanonical.js';
@@ -1,6 +1,24 @@
1
- import type { SyncStatusOptions } from '@powersync/common';
1
+ import type { SyncStatus } from '@powersync/common';
2
+ /**
3
+ * Plain copy of the PowerSync sync status, reported as `status.raw` in JSON output.
4
+ * Keeps the 1.x `SyncStatusOptions` shape (PowerSync 2 made SyncStatus an interface
5
+ * and changed its toJSON() to an internal format).
6
+ */
7
+ export type SyncStatusRaw = {
8
+ connected?: boolean;
9
+ connecting?: boolean;
10
+ hasSynced?: boolean;
11
+ lastSyncedAt?: Date;
12
+ dataFlow?: {
13
+ downloading?: boolean;
14
+ uploading?: boolean;
15
+ downloadError?: Error;
16
+ uploadError?: Error;
17
+ };
18
+ priorityStatusEntries?: SyncStatus['priorityStatusEntries'];
19
+ };
2
20
  import { DinoxError } from '../utils/errors.js';
3
- export type SyncGateFailureReason = 'offline' | 'first-sync-timeout' | 'checkpoint-timeout' | 'data-flow-timeout' | 'not-connected' | 'not-synced' | 'download-error';
21
+ export type SyncGateFailureReason = 'offline' | 'first-sync-timeout' | 'checkpoint-timeout' | 'data-flow-timeout' | 'index-timeout' | 'not-connected' | 'not-synced' | 'download-error';
4
22
  export type SyncGateResult = {
5
23
  ok: boolean;
6
24
  reasons: SyncGateFailureReason[];
@@ -9,6 +27,7 @@ export type SyncGateInput = {
9
27
  offline: boolean;
10
28
  firstSyncStale: boolean;
11
29
  idle: boolean;
30
+ indexComplete?: boolean;
12
31
  recentSync?: boolean;
13
32
  status: {
14
33
  connected: boolean;
@@ -19,7 +38,7 @@ export type SyncGateInput = {
19
38
  message: string;
20
39
  };
21
40
  };
22
- raw?: SyncStatusOptions;
41
+ raw?: SyncStatusRaw;
23
42
  };
24
43
  };
25
44
  export declare function evaluateSyncGate(input: SyncGateInput): SyncGateResult;
@@ -16,6 +16,9 @@ export function evaluateSyncGate(input) {
16
16
  if (!input.idle) {
17
17
  reasons.push('data-flow-timeout');
18
18
  }
19
+ if (input.indexComplete === false) {
20
+ reasons.push('index-timeout');
21
+ }
19
22
  if (!input.status.connected) {
20
23
  reasons.push('not-connected');
21
24
  }
@@ -37,6 +40,6 @@ export function createSyncRequiredError(gate, details) {
37
40
  reasons: gate.reasons,
38
41
  ...(details !== undefined ? { status: details } : {}),
39
42
  },
40
- suggestion: 'Run `dino sync --strict --sync-timeout 600000 --format json`, then retry the command.',
43
+ suggestion: 'Run `dino sync --strict --sync-timeout 20000 --format json`, then retry the command.',
41
44
  });
42
45
  }
@@ -2,6 +2,8 @@ import type { AbstractPowerSyncDatabase } from '@powersync/common';
2
2
  import { type NoteTokenIndexResult } from './tokenIndex.js';
3
3
  export type SyncPassResult = {
4
4
  idle: boolean;
5
+ downloadIdle: boolean;
6
+ uploadIdle: boolean;
5
7
  tokenIndex: NoteTokenIndexResult;
6
8
  };
7
9
  export declare function runSingleSyncPass(db: AbstractPowerSyncDatabase, timeoutMs: number): Promise<SyncPassResult>;
@@ -1,10 +1,21 @@
1
- import { waitForIdleDataFlow } from './runtime.js';
1
+ import { createTimeoutSignal } from '../utils/abort.js';
2
+ import { getStatusSnapshot, waitForDownloadIdle } from './runtime.js';
2
3
  import { syncNoteTokenIndex } from './tokenIndex.js';
3
4
  export async function runSingleSyncPass(db, timeoutMs) {
4
- const idle = await waitForIdleDataFlow(db, Math.min(timeoutMs, 60_000));
5
- const tokenIndex = await syncNoteTokenIndex(db);
5
+ const deadline = Date.now() + Math.max(1, timeoutMs);
6
+ const remainingMs = () => Math.max(0, deadline - Date.now());
7
+ const downloadIdle = await waitForDownloadIdle(db, Math.max(1, Math.min(remainingMs(), 60_000)));
8
+ const indexTimeoutMs = remainingMs();
9
+ const timeout = indexTimeoutMs > 0 ? createTimeoutSignal(indexTimeoutMs) : null;
10
+ const tokenIndex = await syncNoteTokenIndex(db, {
11
+ signal: timeout?.signal ?? AbortSignal.abort(),
12
+ }).finally(() => timeout?.cancel());
13
+ const status = getStatusSnapshot(db);
14
+ const uploadIdle = !status.dataFlowStatus.uploading;
6
15
  return {
7
- idle,
16
+ idle: downloadIdle && uploadIdle,
17
+ downloadIdle,
18
+ uploadIdle,
8
19
  tokenIndex,
9
20
  };
10
21
  }
@@ -1,5 +1,6 @@
1
1
  import type { AbstractPowerSyncDatabase } from '@powersync/common';
2
2
  export type NoteTokenIndexResult = {
3
+ complete: boolean;
3
4
  scanned: number;
4
5
  reindexed: number;
5
6
  skipped: number;
@@ -23,6 +24,7 @@ export declare function syncNoteTokenIndex(db: AbstractPowerSyncDatabase, option
23
24
  batchSize?: number;
24
25
  nowIso?: () => string;
25
26
  tokenize?: (text: string, limit?: number) => string[];
27
+ signal?: AbortSignal;
26
28
  }): Promise<NoteTokenIndexResult>;
27
29
  export declare function inspectNoteTokenIndex(db: AbstractPowerSyncDatabase): Promise<NoteTokenIndexInspection>;
28
30
  export declare function rebuildNoteTokenIndex(db: AbstractPowerSyncDatabase, options?: Parameters<typeof syncNoteTokenIndex>[1]): Promise<NoteTokenIndexResult>;
@@ -9,22 +9,27 @@ export async function syncNoteTokenIndex(db, options) {
9
9
  const batchSize = Math.max(1, Math.trunc(options?.batchSize ?? DEFAULT_BATCH_SIZE));
10
10
  const nowIso = options?.nowIso ?? nowIsoUtc;
11
11
  const tokenize = options?.tokenize ?? tokenizeWithJieba;
12
+ const signal = options?.signal;
13
+ if (signal?.aborted) {
14
+ return createIndexResult('', '', false);
15
+ }
12
16
  await ensureFtsTable(db);
17
+ if (signal?.aborted) {
18
+ return createIndexResult('', '', false);
19
+ }
13
20
  const state = await ensureIndexState(db, nowIso);
14
21
  let cursorUpdatedAt = state.cursor_updated_at ?? '';
15
22
  let cursorId = state.cursor_id ?? '';
16
- const result = {
17
- scanned: 0,
18
- reindexed: 0,
19
- skipped: 0,
20
- removed: 0,
21
- ftsRowsUpserted: 0,
22
- cursor: {
23
- updatedAt: cursorUpdatedAt,
24
- id: cursorId,
25
- },
26
- };
23
+ const result = createIndexResult(cursorUpdatedAt, cursorId, true);
24
+ if (signal?.aborted) {
25
+ result.complete = false;
26
+ return result;
27
+ }
27
28
  while (true) {
29
+ if (signal?.aborted) {
30
+ result.complete = false;
31
+ return result;
32
+ }
28
33
  const rows = await db.getAll(`
29
34
  SELECT
30
35
  id,
@@ -50,23 +55,40 @@ export async function syncNoteTokenIndex(db, options) {
50
55
  break;
51
56
  }
52
57
  for (const row of rows) {
58
+ if (signal?.aborted) {
59
+ result.complete = false;
60
+ await updateIndexCursor(db, cursorUpdatedAt, cursorId, nowIso);
61
+ result.cursor = { updatedAt: cursorUpdatedAt, id: cursorId };
62
+ return result;
63
+ }
53
64
  const sortKey = await indexNoteRow(db, row, result, nowIso, tokenize);
54
65
  cursorUpdatedAt = sortKey;
55
66
  cursorId = row.id;
56
67
  }
57
- await db.execute(`
58
- UPDATE note_local_index_state
59
- SET cursor_updated_at = ?, cursor_id = ?, updated_at = ?
60
- WHERE id = ?
61
- `, [cursorUpdatedAt, cursorId, nowIso(), INDEX_STATE_ID]);
68
+ await updateIndexCursor(db, cursorUpdatedAt, cursorId, nowIso);
69
+ result.cursor = { updatedAt: cursorUpdatedAt, id: cursorId };
62
70
  }
63
- await reconcileSkippedRows(db, result, batchSize, nowIso, tokenize);
71
+ result.complete = await reconcileSkippedRows(db, result, batchSize, nowIso, tokenize, signal);
64
72
  result.cursor = {
65
73
  updatedAt: cursorUpdatedAt,
66
74
  id: cursorId,
67
75
  };
68
76
  return result;
69
77
  }
78
+ function createIndexResult(cursorUpdatedAt, cursorId, complete) {
79
+ return {
80
+ complete,
81
+ scanned: 0,
82
+ reindexed: 0,
83
+ skipped: 0,
84
+ removed: 0,
85
+ ftsRowsUpserted: 0,
86
+ cursor: {
87
+ updatedAt: cursorUpdatedAt,
88
+ id: cursorId,
89
+ },
90
+ };
91
+ }
70
92
  export async function inspectNoteTokenIndex(db) {
71
93
  const notes = await countRows(db, `
72
94
  SELECT COUNT(*) AS count
@@ -154,8 +176,11 @@ async function indexNoteRow(db, row, result, nowIso, tokenize) {
154
176
  }
155
177
  return sortKey;
156
178
  }
157
- async function reconcileSkippedRows(db, result, batchSize, nowIso, tokenize) {
179
+ async function reconcileSkippedRows(db, result, batchSize, nowIso, tokenize, signal) {
158
180
  while (true) {
181
+ if (signal?.aborted) {
182
+ return false;
183
+ }
159
184
  const rows = await db.getAll(`
160
185
  SELECT
161
186
  n.id,
@@ -180,10 +205,16 @@ async function reconcileSkippedRows(db, result, batchSize, nowIso, tokenize) {
180
205
  break;
181
206
  }
182
207
  for (const row of rows) {
208
+ if (signal?.aborted) {
209
+ return false;
210
+ }
183
211
  await indexNoteRow(db, row, result, nowIso, tokenize);
184
212
  }
185
213
  }
186
214
  while (true) {
215
+ if (signal?.aborted) {
216
+ return false;
217
+ }
187
218
  const rows = await db.getAll(`
188
219
  SELECT m.id
189
220
  FROM note_local_index_meta m
@@ -195,11 +226,22 @@ async function reconcileSkippedRows(db, result, batchSize, nowIso, tokenize) {
195
226
  break;
196
227
  }
197
228
  for (const row of rows) {
229
+ if (signal?.aborted) {
230
+ return false;
231
+ }
198
232
  await db.execute(`DELETE FROM ${NOTE_LOCAL_FTS_TABLE} WHERE note_id = ?`, [row.id]);
199
233
  await db.execute('DELETE FROM note_local_index_meta WHERE id = ?', [row.id]);
200
234
  result.removed += 1;
201
235
  }
202
236
  }
237
+ return true;
238
+ }
239
+ async function updateIndexCursor(db, cursorUpdatedAt, cursorId, nowIso) {
240
+ await db.execute(`
241
+ UPDATE note_local_index_state
242
+ SET cursor_updated_at = ?, cursor_id = ?, updated_at = ?
243
+ WHERE id = ?
244
+ `, [cursorUpdatedAt, cursorId, nowIso(), INDEX_STATE_ID]);
203
245
  }
204
246
  async function ensureFtsTable(db) {
205
247
  try {
@@ -1,8 +1,22 @@
1
+ import { type CrudTransaction } from '@powersync/common';
1
2
  import type { UploadHandler } from './connector.js';
3
+ export type UploadOperation = {
4
+ op_id: number;
5
+ op: 'PUT' | 'PATCH' | 'DELETE';
6
+ type: string;
7
+ id: string;
8
+ tx_id?: number;
9
+ data?: Record<string, unknown>;
10
+ old?: Record<string, unknown>;
11
+ old_sha256?: Record<string, string>;
12
+ metadata?: string;
13
+ };
14
+ type CrudOperation = CrudTransaction['crud'][number];
15
+ export declare function toUploadOperation(op: CrudOperation): UploadOperation;
2
16
  export declare function createPowerSyncUploadHandler(options: {
3
17
  authorization: string;
4
18
  uploadBaseUrl: string;
5
- uploadV4Path: string;
6
- uploadV2Path: string;
19
+ uploadPath: string;
7
20
  timeoutMs?: number;
8
21
  }): UploadHandler;
22
+ export {};