@dinoxx/dinox-cli 1.0.22 → 1.1.1
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.
- package/README.md +33 -10
- package/dist/auth/userInfo.d.ts +2 -0
- package/dist/auth/userInfo.js +55 -14
- package/dist/cli.js +36 -2
- package/dist/commands/auth/index.d.ts +35 -0
- package/dist/commands/auth/index.js +382 -83
- package/dist/commands/boxes/index.js +2 -6
- package/dist/commands/boxes/model.d.ts +3 -0
- package/dist/commands/boxes/model.js +16 -1
- package/dist/commands/boxes/operations.js +18 -8
- package/dist/commands/boxes/repo.js +13 -11
- package/dist/commands/boxes/store.js +1 -1
- package/dist/commands/config/index.js +7 -5
- package/dist/commands/descriptor/register.js +9 -0
- package/dist/commands/doctor.d.ts +123 -0
- package/dist/commands/doctor.js +539 -0
- package/dist/commands/graph/index.d.ts +1 -1
- package/dist/commands/graph/index.js +35 -21
- package/dist/commands/graph/repo.js +92 -17
- package/dist/commands/meta/index.js +4 -4
- package/dist/commands/meta/repo.js +4 -3
- package/dist/commands/notes/actions.d.ts +1 -1
- package/dist/commands/notes/actions.js +121 -78
- package/dist/commands/notes/bulk.d.ts +1 -0
- package/dist/commands/notes/bulk.js +23 -17
- package/dist/commands/notes/contentEngine.js +69 -11
- package/dist/commands/notes/contentPatch.d.ts +4 -1
- package/dist/commands/notes/contentPatch.js +105 -41
- package/dist/commands/notes/contentPatchCommand.js +28 -11
- package/dist/commands/notes/descriptors.js +50 -20
- package/dist/commands/notes/dryRun.d.ts +1 -0
- package/dist/commands/notes/dryRun.js +4 -7
- package/dist/commands/notes/export.d.ts +6 -0
- package/dist/commands/notes/export.js +26 -6
- package/dist/commands/notes/metadataMutation.d.ts +1 -0
- package/dist/commands/notes/metadataMutation.js +14 -3
- package/dist/commands/notes/repo.d.ts +46 -4
- package/dist/commands/notes/repo.js +113 -28
- package/dist/commands/notes/runtime.d.ts +2 -1
- package/dist/commands/notes/runtime.js +17 -1
- package/dist/commands/notes/searchSql.js +13 -6
- package/dist/commands/notes/writeReceipt.d.ts +20 -0
- package/dist/commands/notes/writeReceipt.js +82 -0
- package/dist/commands/prompt/index.js +3 -3
- package/dist/commands/prompt/repo.d.ts +4 -1
- package/dist/commands/prompt/repo.js +17 -7
- package/dist/commands/runtime.d.ts +14 -2
- package/dist/commands/runtime.js +89 -19
- package/dist/commands/schema/renderSkills.js +5 -2
- package/dist/commands/schema/spec.js +4 -0
- package/dist/commands/storage/index.js +8 -2
- package/dist/commands/storage/repo.d.ts +4 -0
- package/dist/commands/storage/repo.js +356 -92
- package/dist/commands/sync.d.ts +23 -1
- package/dist/commands/sync.js +105 -60
- package/dist/commands/tags/content.js +9 -0
- package/dist/commands/tags/index.js +2 -6
- package/dist/commands/tags/operations.js +15 -10
- package/dist/commands/tags/repo.d.ts +2 -0
- package/dist/commands/tags/repo.js +18 -5
- package/dist/commands/tags/store.js +1 -1
- package/dist/commands/todo/contentModel.d.ts +4 -3
- package/dist/commands/todo/contentModel.js +78 -28
- package/dist/commands/todo/dryRun.d.ts +1 -0
- package/dist/commands/todo/dryRun.js +17 -13
- package/dist/commands/todo/index.d.ts +6 -0
- package/dist/commands/todo/index.js +89 -123
- package/dist/commands/todo/repo.d.ts +36 -1
- package/dist/commands/todo/repo.js +146 -37
- package/dist/commands/todo/taskIdentity.d.ts +2 -0
- package/dist/commands/todo/taskIdentity.js +64 -0
- package/dist/commands/todo/taskModel.js +27 -17
- package/dist/commands/update.d.ts +13 -1
- package/dist/commands/update.js +135 -23
- package/dist/commands/writeDryRun.d.ts +3 -2
- package/dist/commands/writeDryRun.js +4 -3
- package/dist/commands/writeDurability.d.ts +5 -0
- package/dist/commands/writeDurability.js +22 -0
- package/dist/config/paths.js +6 -1
- package/dist/config/resolve.d.ts +2 -0
- package/dist/config/resolve.js +23 -9
- package/dist/config/store.d.ts +3 -0
- package/dist/config/store.js +61 -14
- package/dist/config/types.d.ts +4 -0
- package/dist/daemon/client.d.ts +26 -1
- package/dist/daemon/client.js +236 -12
- package/dist/daemon/ensure.js +74 -12
- package/dist/daemon/index.d.ts +42 -0
- package/dist/daemon/index.js +202 -52
- package/dist/daemon/lifecycle.d.ts +44 -0
- package/dist/daemon/lifecycle.js +118 -0
- package/dist/daemon/pid.d.ts +19 -6
- package/dist/daemon/pid.js +147 -13
- package/dist/daemon/route.d.ts +14 -0
- package/dist/daemon/route.js +40 -0
- package/dist/daemon/server.d.ts +11 -0
- package/dist/daemon/server.js +201 -50
- package/dist/daemon/types.d.ts +29 -1
- package/dist/daemon/types.js +1 -0
- package/dist/dinox.js +25 -1
- package/dist/powersync/connector.js +31 -16
- package/dist/powersync/exclusiveRuntime.d.ts +20 -0
- package/dist/powersync/exclusiveRuntime.js +48 -0
- package/dist/powersync/runtime.d.ts +25 -4
- package/dist/powersync/runtime.js +255 -35
- package/dist/powersync/syncGate.d.ts +4 -1
- package/dist/powersync/syncGate.js +11 -2
- package/dist/powersync/syncPass.d.ts +2 -0
- package/dist/powersync/syncPass.js +15 -4
- package/dist/powersync/tokenIndex.d.ts +13 -0
- package/dist/powersync/tokenIndex.js +216 -37
- package/dist/powersync/uploader.js +107 -52
- package/dist/utils/abort.js +0 -4
- package/dist/utils/asyncRelease.d.ts +2 -0
- package/dist/utils/asyncRelease.js +25 -0
- package/dist/utils/bidlinkCanonicalization.js +3 -0
- package/dist/utils/dryRun.d.ts +1 -1
- package/dist/utils/errors.d.ts +15 -1
- package/dist/utils/errors.js +223 -5
- package/dist/utils/output.d.ts +1 -0
- package/dist/utils/output.js +51 -15
- package/dist/utils/redact.js +1 -1
- package/dist/utils/sqliteLease.d.ts +8 -0
- package/dist/utils/sqliteLease.js +59 -0
- package/dist/utils/syncTimeout.d.ts +7 -1
- package/dist/utils/syncTimeout.js +8 -7
- package/dist/utils/terminalSanitization.js +6 -2
- package/dist/utils/tiptapMarkdown.js +49 -3
- package/dist/utils/tiptapMarkdownSyntax.d.ts +9 -0
- package/dist/utils/tiptapMarkdownSyntax.js +249 -0
- package/dist/utils/tokenize.js +24 -2
- package/dist/utils/updateNotice.js +60 -12
- package/package.json +14 -10
- package/dist/commands/mcp/auth.d.ts +0 -4
- package/dist/commands/mcp/auth.js +0 -75
- package/dist/commands/mcp/index.d.ts +0 -2
- package/dist/commands/mcp/index.js +0 -86
- package/dist/commands/mcp/noteContentTools.d.ts +0 -222
- package/dist/commands/mcp/noteContentTools.js +0 -390
- package/dist/commands/mcp/server.d.ts +0 -34
- package/dist/commands/mcp/server.js +0 -424
- package/dist/commands/mcp/tools.d.ts +0 -2
- package/dist/commands/mcp/tools.js +0 -32
- package/dist/commands/mcp/types.d.ts +0 -39
- package/dist/commands/mcp/types.js +0 -1
- package/dist/utils/noteContentEngine.d.ts +0 -333
- package/dist/utils/noteContentEngine.js +0 -740
package/dist/commands/runtime.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { hydrateResolvedAuthIdentity } from '../auth/userInfo.js';
|
|
2
2
|
import { loadConfig } from '../config/store.js';
|
|
3
3
|
import { resolveConfig } from '../config/resolve.js';
|
|
4
|
-
import {
|
|
4
|
+
import { withExclusivePowerSync } from '../powersync/exclusiveRuntime.js';
|
|
5
|
+
import { getStatusSnapshot, waitForDownloadIdle, waitForLastSyncedAfter, waitForUploadQueueEmpty, } from '../powersync/runtime.js';
|
|
5
6
|
import { createSyncRequiredError, evaluateSyncGate } from '../powersync/syncGate.js';
|
|
6
7
|
import { syncNoteTokenIndex } from '../powersync/tokenIndex.js';
|
|
7
|
-
import {
|
|
8
|
+
import { createTimeoutSignal } from '../utils/abort.js';
|
|
9
|
+
import { DinoxError } from '../utils/errors.js';
|
|
10
|
+
import { printHumanReadableWarning } from '../utils/output.js';
|
|
8
11
|
import { parseSyncTimeoutMs } from '../utils/syncTimeout.js';
|
|
12
|
+
import { parseWriteDurability } from './writeDurability.js';
|
|
9
13
|
const PRE_SYNC_TIMEOUT_MS = 10_000;
|
|
10
14
|
const POST_WRITE_IDLE_TIMEOUT_MS = 5_000;
|
|
11
15
|
function isCommandExecutionContext(source) {
|
|
@@ -26,7 +30,19 @@ function resolveGlobals(source) {
|
|
|
26
30
|
export function commandStale(runtime) {
|
|
27
31
|
return runtime.offline ? true : runtime.stale;
|
|
28
32
|
}
|
|
33
|
+
export function resolveWriteDurabilityForRuntime(runtime, value) {
|
|
34
|
+
const durability = parseWriteDurability(value);
|
|
35
|
+
if (runtime.offline && durability === 'uploaded') {
|
|
36
|
+
throw new DinoxError('--durability uploaded cannot be used with --offline', {
|
|
37
|
+
code: 'USAGE_ERROR',
|
|
38
|
+
suggestion: 'Remove --offline or use --durability local for local-only writes.',
|
|
39
|
+
recoverable: true,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return durability;
|
|
43
|
+
}
|
|
29
44
|
export async function withCommandRuntime(source, run) {
|
|
45
|
+
const startedAtIso = new Date().toISOString();
|
|
30
46
|
const globals = resolveGlobals(source);
|
|
31
47
|
const rawConfig = await loadConfig();
|
|
32
48
|
const baseConfig = resolveConfig(rawConfig);
|
|
@@ -36,8 +52,12 @@ export async function withCommandRuntime(source, run) {
|
|
|
36
52
|
const { config } = offline
|
|
37
53
|
? { config: baseConfig }
|
|
38
54
|
: await hydrateResolvedAuthIdentity(baseConfig, { timeoutMs });
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
return withExclusivePowerSync({
|
|
56
|
+
config,
|
|
57
|
+
offline,
|
|
58
|
+
timeoutMs,
|
|
59
|
+
expectedTokenFingerprint: config.auth.tokenFingerprint ?? null,
|
|
60
|
+
}, async ({ db, stale }) => {
|
|
41
61
|
return await run({
|
|
42
62
|
db,
|
|
43
63
|
config,
|
|
@@ -49,13 +69,12 @@ export async function withCommandRuntime(source, run) {
|
|
|
49
69
|
sync: {
|
|
50
70
|
firstSyncStale: stale,
|
|
51
71
|
preSyncIdle: null,
|
|
72
|
+
recentSync: null,
|
|
52
73
|
gate: null,
|
|
74
|
+
startedAtIso,
|
|
53
75
|
},
|
|
54
76
|
});
|
|
55
|
-
}
|
|
56
|
-
finally {
|
|
57
|
-
await db.close().catch(() => undefined);
|
|
58
|
-
}
|
|
77
|
+
});
|
|
59
78
|
}
|
|
60
79
|
export async function syncBeforeCommand(runtime, options = {}) {
|
|
61
80
|
if (runtime.offline) {
|
|
@@ -64,7 +83,9 @@ export async function syncBeforeCommand(runtime, options = {}) {
|
|
|
64
83
|
offline: true,
|
|
65
84
|
firstSyncStale: runtime.sync.firstSyncStale,
|
|
66
85
|
idle: false,
|
|
86
|
+
recentSync: false,
|
|
67
87
|
status: {
|
|
88
|
+
connected: false,
|
|
68
89
|
hasSynced: false,
|
|
69
90
|
dataFlowStatus: {},
|
|
70
91
|
},
|
|
@@ -74,16 +95,31 @@ export async function syncBeforeCommand(runtime, options = {}) {
|
|
|
74
95
|
}
|
|
75
96
|
return;
|
|
76
97
|
}
|
|
77
|
-
const
|
|
78
|
-
|
|
98
|
+
const timeoutMs = Math.min(runtime.timeoutMs, options.timeoutMs ?? PRE_SYNC_TIMEOUT_MS);
|
|
99
|
+
const deadlineAtMs = Date.now() + timeoutMs;
|
|
100
|
+
const remainingTimeoutMs = () => Math.max(0, deadlineAtMs - Date.now());
|
|
101
|
+
const recentSync = runtime.requireSync
|
|
102
|
+
? await waitForLastSyncedAfter(runtime.db, runtime.sync.startedAtIso, Math.max(1, remainingTimeoutMs()))
|
|
103
|
+
: true;
|
|
104
|
+
runtime.sync.recentSync = recentSync;
|
|
105
|
+
const downloadIdle = await waitForDownloadIdle(runtime.db, Math.max(1, remainingTimeoutMs()));
|
|
106
|
+
runtime.sync.preSyncIdle = downloadIdle;
|
|
107
|
+
let indexComplete;
|
|
79
108
|
if (options.syncTokenIndex) {
|
|
80
|
-
|
|
109
|
+
const indexTimeoutMs = remainingTimeoutMs();
|
|
110
|
+
const timeout = indexTimeoutMs > 0 ? createTimeoutSignal(indexTimeoutMs) : null;
|
|
111
|
+
const tokenIndex = await syncNoteTokenIndex(runtime.db, {
|
|
112
|
+
signal: timeout?.signal ?? AbortSignal.abort(),
|
|
113
|
+
}).finally(() => timeout?.cancel());
|
|
114
|
+
indexComplete = tokenIndex.complete;
|
|
81
115
|
}
|
|
82
116
|
const status = getStatusSnapshot(runtime.db);
|
|
83
117
|
const gate = evaluateSyncGate({
|
|
84
118
|
offline: runtime.offline,
|
|
85
119
|
firstSyncStale: runtime.sync.firstSyncStale,
|
|
86
|
-
idle,
|
|
120
|
+
idle: downloadIdle,
|
|
121
|
+
indexComplete,
|
|
122
|
+
recentSync,
|
|
87
123
|
status,
|
|
88
124
|
});
|
|
89
125
|
runtime.sync.gate = gate;
|
|
@@ -93,18 +129,52 @@ export async function syncBeforeCommand(runtime, options = {}) {
|
|
|
93
129
|
}
|
|
94
130
|
}
|
|
95
131
|
export async function waitForMutationUpload(runtime, options = {}) {
|
|
132
|
+
const requestedDurability = resolveWriteDurabilityForRuntime(runtime, options.durability);
|
|
96
133
|
if (runtime.offline) {
|
|
97
|
-
return;
|
|
134
|
+
return { durability: 'local', upload_queue_remaining: null };
|
|
98
135
|
}
|
|
99
|
-
await
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
136
|
+
const result = await waitForUploadQueueEmpty(runtime.db, Math.min(runtime.timeoutMs, options.timeoutMs
|
|
137
|
+
?? (runtime.requireSync || requestedDurability === 'uploaded'
|
|
138
|
+
? runtime.timeoutMs
|
|
139
|
+
: POST_WRITE_IDLE_TIMEOUT_MS)));
|
|
140
|
+
if (result.ok) {
|
|
141
|
+
return { durability: 'uploaded', upload_queue_remaining: 0 };
|
|
142
|
+
}
|
|
143
|
+
const uploadError = result.uploadError
|
|
144
|
+
? { name: result.uploadError.name, message: result.uploadError.message }
|
|
145
|
+
: undefined;
|
|
146
|
+
const details = {
|
|
147
|
+
pendingCount: result.pendingCount,
|
|
148
|
+
timedOut: result.timedOut,
|
|
149
|
+
...(uploadError ? { uploadError } : {}),
|
|
150
|
+
...(result.queueError ? { queueError: result.queueError } : {}),
|
|
151
|
+
};
|
|
152
|
+
const message = result.queueError
|
|
153
|
+
? `Changes were saved locally, but the upload queue could not be verified: ${result.queueError.message}`
|
|
154
|
+
: result.uploadError
|
|
155
|
+
? `Changes were saved locally, but upload failed: ${result.uploadError.message}`
|
|
156
|
+
: `Changes were saved locally, but ${result.pendingCount ?? 'an unknown number of'} pending upload(s) did not finish before timeout.`;
|
|
157
|
+
if (runtime.requireSync || requestedDurability === 'uploaded') {
|
|
158
|
+
throw new DinoxError(message, {
|
|
159
|
+
code: 'UPLOAD_PENDING',
|
|
160
|
+
details,
|
|
161
|
+
suggestion: 'Check network connectivity and retry with a larger --sync-timeout.',
|
|
162
|
+
suggestedAction: {
|
|
163
|
+
command: 'dino doctor --fix --format json',
|
|
164
|
+
reason: 'Inspect sync health and wait for pending local uploads before retrying the write.',
|
|
165
|
+
},
|
|
166
|
+
recoverable: true,
|
|
167
|
+
});
|
|
104
168
|
}
|
|
169
|
+
printHumanReadableWarning(`warning: ${message}`);
|
|
170
|
+
return {
|
|
171
|
+
durability: 'local',
|
|
172
|
+
upload_queue_remaining: result.pendingCount,
|
|
173
|
+
...(uploadError ? { upload_error: uploadError } : {}),
|
|
174
|
+
};
|
|
105
175
|
}
|
|
106
176
|
export function printStaleCacheWarning(runtime, message = 'warning: sync timed out; local cache may be stale') {
|
|
107
177
|
if (runtime.stale && !runtime.offline) {
|
|
108
|
-
|
|
178
|
+
printHumanReadableWarning(message);
|
|
109
179
|
}
|
|
110
180
|
}
|
|
@@ -4,6 +4,7 @@ import { listCommandSchemas } from './spec.js';
|
|
|
4
4
|
const SECTION_ORDER = [
|
|
5
5
|
{ title: 'Auth', paths: ['auth.login', 'auth.logout', 'auth.status'] },
|
|
6
6
|
{ title: 'Daemon', paths: ['daemon.start', 'daemon.status', 'daemon.restart', 'daemon.stop'] },
|
|
7
|
+
{ title: 'Doctor', paths: ['doctor'] },
|
|
7
8
|
{ title: 'Sync', paths: ['sync'] },
|
|
8
9
|
{ title: 'Schema', paths: ['schema'] },
|
|
9
10
|
{ title: 'Update CLI', paths: ['update'] },
|
|
@@ -15,6 +16,7 @@ const SECTION_ORDER = [
|
|
|
15
16
|
{ title: 'Storage', paths: ['storage.list', 'storage.test', 'storage.upload', 'storage.stats'] },
|
|
16
17
|
{ title: 'Config', paths: ['config.get', 'config.set'] },
|
|
17
18
|
{ title: 'Info', paths: ['info'] },
|
|
19
|
+
{ title: 'Metadata', paths: ['meta.stats', 'meta.schema'] },
|
|
18
20
|
{ title: 'Graph', paths: ['graph.backlinks', 'graph.outlinks', 'graph.related', 'graph.stats'] },
|
|
19
21
|
];
|
|
20
22
|
const GLOBAL_OPTIONS = [
|
|
@@ -90,7 +92,7 @@ const GENERATED_COMMAND_SECTIONS = {
|
|
|
90
92
|
'Use `--boxes` for public box filters.',
|
|
91
93
|
'Prefer `--fields id,title,summary,tags,created_at,boxes,is_starred` when the user only needs search metadata.',
|
|
92
94
|
'Use `note export` for backup or migration; Markdown exports include frontmatter, JSON exports preserve note metadata and content JSON.',
|
|
93
|
-
'Use `note content-read` immediately before `note patch`; the returned readToken, content hash, block index, outline, and resolved hashtag paths are the required edit context.',
|
|
95
|
+
'Use `note content-read` immediately before `note patch`; the returned single-use readToken, content hash, block index, outline, and resolved hashtag paths are the required edit context. Run `content-read` again after every patch attempt.',
|
|
94
96
|
'`--sql` remains storage-oriented and still uses the field name `zettel_boxes`.',
|
|
95
97
|
],
|
|
96
98
|
},
|
|
@@ -113,7 +115,7 @@ const GENERATED_COMMAND_SECTIONS = {
|
|
|
113
115
|
'`note update` is for explicit note ids and full metadata replacement. It is not an append command.',
|
|
114
116
|
'`note tag` and `note move` are explicit-id incremental organizers: add/remove preserves existing values, replace overwrites the whole list.',
|
|
115
117
|
'`note move` changes zettel box membership only; it does not move files or note content.',
|
|
116
|
-
'`note patch` is only for structured content edits. Run `note content-read` immediately before it
|
|
118
|
+
'`note patch` is only for structured content edits. Run `note content-read` immediately before it and pass `--read-token` for real writes. The token is single-use and is consumed before any real patch attempt, so run `content-read` again after every failed attempt. Use `--allow-protected-replace` only after reviewing protected blocks.',
|
|
117
119
|
'`note bulk` is for filter-based batch metadata organization; it never accepts `--sql`, and real writes require `--confirm --expected-count <n>`.',
|
|
118
120
|
'Prefer `note star` / `note unstar` for pure starring changes, and `note update` when multiple fields change together.',
|
|
119
121
|
'Run the same command with `--dry-run --format json` first.',
|
|
@@ -134,6 +136,7 @@ const GENERATED_COMMAND_SECTIONS = {
|
|
|
134
136
|
notes: [
|
|
135
137
|
'Run the same command with `--dry-run` first.',
|
|
136
138
|
'For append, prefer explicit `--note-id` unless the user confirms the default target behavior.',
|
|
139
|
+
'For update, pass the `note_id` returned by todo search as `--note-id` when available; broad task lookup is bounded and refuses truncated results. Legacy ids bind to the searched task snapshot, so search again after the note changes.',
|
|
137
140
|
],
|
|
138
141
|
},
|
|
139
142
|
};
|
|
@@ -4,8 +4,10 @@ import { commandSchemasFromGroupDescriptor } from '../descriptor/register.js';
|
|
|
4
4
|
import { standaloneCommandSchemaFromDescriptor } from '../descriptor/register.js';
|
|
5
5
|
import { configCommandGroup } from '../config/index.js';
|
|
6
6
|
import { daemonCommandGroup } from '../../daemon/index.js';
|
|
7
|
+
import { doctorCommandDescriptor } from '../doctor.js';
|
|
7
8
|
import { graphCommandGroup } from '../graph/index.js';
|
|
8
9
|
import { infoCommandDescriptor } from '../info/index.js';
|
|
10
|
+
import { metaCommandGroup } from '../meta/index.js';
|
|
9
11
|
import { noteCommandGroup } from '../notes/index.js';
|
|
10
12
|
import { promptCommandGroup } from '../prompt/index.js';
|
|
11
13
|
import { schemaCommandMetadata } from './commandMetadata.js';
|
|
@@ -18,10 +20,12 @@ export const COMMAND_SCHEMAS = [
|
|
|
18
20
|
...commandSchemasFromGroupDescriptor(authCommandGroup),
|
|
19
21
|
...commandSchemasFromGroupDescriptor(configCommandGroup),
|
|
20
22
|
...commandSchemasFromGroupDescriptor(daemonCommandGroup),
|
|
23
|
+
standaloneCommandSchemaFromDescriptor(doctorCommandDescriptor),
|
|
21
24
|
standaloneCommandSchemaFromDescriptor(syncCommandDescriptor),
|
|
22
25
|
standaloneCommandSchemaFromDescriptor({ ...schemaCommandMetadata, action: async () => undefined }),
|
|
23
26
|
standaloneCommandSchemaFromDescriptor(infoCommandDescriptor),
|
|
24
27
|
standaloneCommandSchemaFromDescriptor(updateCommandDescriptor),
|
|
28
|
+
...commandSchemasFromGroupDescriptor(metaCommandGroup),
|
|
25
29
|
...commandSchemasFromGroupDescriptor(tagCommandGroup),
|
|
26
30
|
...commandSchemasFromGroupDescriptor(boxCommandGroup),
|
|
27
31
|
...commandSchemasFromGroupDescriptor(promptCommandGroup),
|
|
@@ -5,7 +5,7 @@ import { buildStorageTestDryRunPreview, buildStorageUploadDryRunPreview } from '
|
|
|
5
5
|
import { printDryRunPreview } from '../../utils/dryRun.js';
|
|
6
6
|
import { DinoxError } from '../../utils/errors.js';
|
|
7
7
|
import { getRequestedStructuredOutputFormat, printHumanReadableLine, printSuccess, } from '../../utils/output.js';
|
|
8
|
-
import { commandStale, printStaleCacheWarning,
|
|
8
|
+
import { commandStale, printStaleCacheWarning, syncBeforeCommand, waitForMutationUpload, withCommandRuntime, } from '../runtime.js';
|
|
9
9
|
import { getStorageStats, inspectStorageTest, inspectStorageUpload, listStorageConfigs, parseStorageUploadCategory, testStorageUpload, uploadFileToStorage, } from './repo.js';
|
|
10
10
|
const STORAGE_GLOBAL_OPTIONS = [...FORMAT_OPTIONS, ...OFFLINE_OPTIONS, ...REQUIRE_SYNC_OPTIONS, ...SYNC_TIMEOUT_OPTIONS];
|
|
11
11
|
async function runStorageList(context) {
|
|
@@ -24,6 +24,9 @@ async function runStorageUpload(context) {
|
|
|
24
24
|
throw new DinoxError('File path is required. Use `dino storage upload <file>`.');
|
|
25
25
|
}
|
|
26
26
|
const options = context.options;
|
|
27
|
+
if (options.overwrite && !options.key?.trim()) {
|
|
28
|
+
throw new DinoxError('--overwrite requires an explicit --key.');
|
|
29
|
+
}
|
|
27
30
|
const category = parseStorageUploadCategory(options.category ?? 'files');
|
|
28
31
|
const structuredOutput = getRequestedStructuredOutputFormat() !== null;
|
|
29
32
|
await withCommandRuntime(context, async (runtime) => {
|
|
@@ -49,6 +52,7 @@ async function runStorageUpload(context) {
|
|
|
49
52
|
storageKey: plan.storageKey,
|
|
50
53
|
storageUrl: plan.storageUrl,
|
|
51
54
|
selectionSource: plan.selectionSource,
|
|
55
|
+
overwrite: options.overwrite === true,
|
|
52
56
|
}));
|
|
53
57
|
return;
|
|
54
58
|
}
|
|
@@ -58,8 +62,8 @@ async function runStorageUpload(context) {
|
|
|
58
62
|
category,
|
|
59
63
|
storageId: options.storageId,
|
|
60
64
|
key: options.key,
|
|
65
|
+
overwrite: options.overwrite,
|
|
61
66
|
});
|
|
62
|
-
printUploadDisabledWarning(runtime, 'warning: upload disabled (powersync.uploadBaseUrl is unset); resource metadata is local-only for now');
|
|
63
67
|
await waitForMutationUpload(runtime);
|
|
64
68
|
const payload = {
|
|
65
69
|
ok: true,
|
|
@@ -219,6 +223,7 @@ export const storageCommandGroup = {
|
|
|
219
223
|
{ flags: '--storage-id <id>', description: 'Explicit storage config id (otherwise use active custom config)', type: 'string' },
|
|
220
224
|
{ flags: '--category <kind>', description: 'Upload category: images|audios|files|videos', type: 'string', defaultValue: 'files', enum: ['images', 'audios', 'files', 'videos'] },
|
|
221
225
|
{ flags: '--key <string>', description: 'Explicit object key override', type: 'string' },
|
|
226
|
+
{ flags: '--overwrite', description: 'Replace existing objects addressed by an explicit --key', type: 'boolean' },
|
|
222
227
|
{ flags: '--dry-run', description: 'Preview the upload target and resource record without uploading', type: 'boolean' },
|
|
223
228
|
],
|
|
224
229
|
schema: {
|
|
@@ -234,6 +239,7 @@ export const storageCommandGroup = {
|
|
|
234
239
|
examples: [
|
|
235
240
|
'dino storage upload ./report.pdf --format json --dry-run',
|
|
236
241
|
'dino storage upload ./photo.jpg --category images --storage-id <id> --format json',
|
|
242
|
+
'dino storage upload ./report.pdf --key imports/report.pdf --overwrite --format json',
|
|
237
243
|
],
|
|
238
244
|
},
|
|
239
245
|
action: runStorageUpload,
|
|
@@ -113,6 +113,7 @@ type UploadObjectInput = {
|
|
|
113
113
|
key: string;
|
|
114
114
|
contentType: string;
|
|
115
115
|
contentLength: number;
|
|
116
|
+
overwrite: boolean;
|
|
116
117
|
storage: StoredCustomStorageConfig;
|
|
117
118
|
};
|
|
118
119
|
type UploadObjectResult = {
|
|
@@ -124,6 +125,7 @@ type UploadDeps = {
|
|
|
124
125
|
deleteObject?: (input: {
|
|
125
126
|
bucket: string;
|
|
126
127
|
key: string;
|
|
128
|
+
etag?: string | null;
|
|
127
129
|
storage: StoredCustomStorageConfig;
|
|
128
130
|
}) => Promise<void>;
|
|
129
131
|
uploadBytes?: (input: {
|
|
@@ -131,6 +133,7 @@ type UploadDeps = {
|
|
|
131
133
|
bucket: string;
|
|
132
134
|
key: string;
|
|
133
135
|
contentType: string;
|
|
136
|
+
overwrite?: boolean;
|
|
134
137
|
storage: StoredCustomStorageConfig;
|
|
135
138
|
}) => Promise<UploadObjectResult>;
|
|
136
139
|
};
|
|
@@ -158,5 +161,6 @@ export declare function uploadFileToStorage(db: AbstractPowerSyncDatabase, input
|
|
|
158
161
|
category: StorageUploadCategory;
|
|
159
162
|
storageId?: string;
|
|
160
163
|
key?: string;
|
|
164
|
+
overwrite?: boolean;
|
|
161
165
|
}, deps?: UploadDeps): Promise<StorageUploadResult>;
|
|
162
166
|
export {};
|