@wafflebase/cli 0.4.9 → 0.5.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/dist/bin.js +99988 -11
- package/package.json +7 -6
- package/dist/bin.d.ts +0 -2
- package/dist/client/dry-run.d.ts +0 -5
- package/dist/client/dry-run.js +0 -16
- package/dist/client/http-client.d.ts +0 -59
- package/dist/client/http-client.js +0 -178
- package/dist/commands/api-keys.d.ts +0 -2
- package/dist/commands/api-keys.js +0 -54
- package/dist/commands/cells.d.ts +0 -2
- package/dist/commands/cells.js +0 -108
- package/dist/commands/ctx.d.ts +0 -5
- package/dist/commands/ctx.js +0 -56
- package/dist/commands/docs.d.ts +0 -3
- package/dist/commands/docs.js +0 -320
- package/dist/commands/login.d.ts +0 -2
- package/dist/commands/login.js +0 -220
- package/dist/commands/logout.d.ts +0 -2
- package/dist/commands/logout.js +0 -10
- package/dist/commands/root.d.ts +0 -18
- package/dist/commands/root.js +0 -37
- package/dist/commands/schema.d.ts +0 -2
- package/dist/commands/schema.js +0 -28
- package/dist/commands/sheets-export.d.ts +0 -2
- package/dist/commands/sheets-export.js +0 -52
- package/dist/commands/sheets-import.d.ts +0 -2
- package/dist/commands/sheets-import.js +0 -88
- package/dist/commands/sheets.d.ts +0 -2
- package/dist/commands/sheets.js +0 -17
- package/dist/commands/slides.d.ts +0 -3
- package/dist/commands/slides.js +0 -227
- package/dist/commands/status.d.ts +0 -2
- package/dist/commands/status.js +0 -22
- package/dist/commands/tabs.d.ts +0 -2
- package/dist/commands/tabs.js +0 -20
- package/dist/config/config.d.ts +0 -38
- package/dist/config/config.js +0 -135
- package/dist/config/session.d.ts +0 -49
- package/dist/config/session.js +0 -74
- package/dist/docs/content.d.ts +0 -37
- package/dist/docs/content.js +0 -90
- package/dist/docs/docx-export.d.ts +0 -23
- package/dist/docs/docx-export.js +0 -14
- package/dist/docs/docx-import.d.ts +0 -36
- package/dist/docs/docx-import.js +0 -70
- package/dist/docs/dom-polyfill.d.ts +0 -1
- package/dist/docs/dom-polyfill.js +0 -29
- package/dist/docs/fontkit-measurer.d.ts +0 -41
- package/dist/docs/fontkit-measurer.js +0 -64
- package/dist/docs/image-fetcher.d.ts +0 -37
- package/dist/docs/image-fetcher.js +0 -38
- package/dist/docs/import.d.ts +0 -72
- package/dist/docs/import.js +0 -146
- package/dist/docs/page-range.d.ts +0 -29
- package/dist/docs/page-range.js +0 -74
- package/dist/docs/page-slice.d.ts +0 -45
- package/dist/docs/page-slice.js +0 -61
- package/dist/docs/paginate.d.ts +0 -13
- package/dist/docs/paginate.js +0 -19
- package/dist/docs/pdf-export.d.ts +0 -47
- package/dist/docs/pdf-export.js +0 -95
- package/dist/output/binary.d.ts +0 -37
- package/dist/output/binary.js +0 -47
- package/dist/output/csv.d.ts +0 -4
- package/dist/output/csv.js +0 -25
- package/dist/output/formatter.d.ts +0 -4
- package/dist/output/formatter.js +0 -41
- package/dist/output/json.d.ts +0 -1
- package/dist/output/json.js +0 -3
- package/dist/output/table.d.ts +0 -4
- package/dist/output/table.js +0 -14
- package/dist/schema/registry.d.ts +0 -42
- package/dist/schema/registry.js +0 -375
- package/dist/slides/content.d.ts +0 -41
- package/dist/slides/content.js +0 -122
- package/dist/slides/import.d.ts +0 -82
- package/dist/slides/import.js +0 -170
- package/dist/slides/pptx-export.d.ts +0 -6
- package/dist/slides/pptx-export.js +0 -10
- package/dist/slides/pptx-import.d.ts +0 -35
- package/dist/slides/pptx-import.js +0 -49
- package/dist/util/csv-parse.d.ts +0 -21
- package/dist/util/csv-parse.js +0 -99
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wafflebase/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "CLI for Wafflebase spreadsheet API",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -19,9 +19,7 @@
|
|
|
19
19
|
"fontkit": "^2.0.4",
|
|
20
20
|
"open": "^11.0.0",
|
|
21
21
|
"pdf-lib": "^1.17.1",
|
|
22
|
-
"yaml": "^2.0.0"
|
|
23
|
-
"@wafflebase/docs": "0.4.9",
|
|
24
|
-
"@wafflebase/slides": "0.4.9"
|
|
22
|
+
"yaml": "^2.0.0"
|
|
25
23
|
},
|
|
26
24
|
"devDependencies": {
|
|
27
25
|
"@types/fontkit": "^2.0.0",
|
|
@@ -29,12 +27,15 @@
|
|
|
29
27
|
"@vitest/coverage-v8": "4.1.8",
|
|
30
28
|
"eslint": "^9.18.0",
|
|
31
29
|
"jszip": "^3.10.1",
|
|
30
|
+
"tsup": "^8.5.1",
|
|
32
31
|
"tsx": "^4.19.0",
|
|
33
32
|
"typescript": "^5.9.3",
|
|
34
|
-
"vitest": "^4.1.8"
|
|
33
|
+
"vitest": "^4.1.8",
|
|
34
|
+
"@wafflebase/docs": "0.5.1",
|
|
35
|
+
"@wafflebase/slides": "0.5.1"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
|
-
"build": "
|
|
38
|
+
"build": "tsup",
|
|
38
39
|
"dev": "tsx src/bin.ts",
|
|
39
40
|
"test": "vitest --run",
|
|
40
41
|
"test:watch": "vitest",
|
package/dist/bin.d.ts
DELETED
package/dist/client/dry-run.d.ts
DELETED
package/dist/client/dry-run.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Print the request that would be sent without executing it.
|
|
3
|
-
*/
|
|
4
|
-
export function printDryRun(config, method, path, body) {
|
|
5
|
-
const server = config.server.replace(/\/$/, '');
|
|
6
|
-
const url = `${server}/api/v1/workspaces/${config.workspace}${path}`;
|
|
7
|
-
const output = {
|
|
8
|
-
dry_run: true,
|
|
9
|
-
method,
|
|
10
|
-
url,
|
|
11
|
-
};
|
|
12
|
-
if (body !== undefined) {
|
|
13
|
-
output.body = body;
|
|
14
|
-
}
|
|
15
|
-
console.log(JSON.stringify(output, null, 2));
|
|
16
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { Document } from '@wafflebase/docs';
|
|
2
|
-
import type { SlidesDocument } from '@wafflebase/slides/node';
|
|
3
|
-
import type { CliConfig } from '../config/config.js';
|
|
4
|
-
export interface ApiResponse<T = unknown> {
|
|
5
|
-
ok: boolean;
|
|
6
|
-
status: number;
|
|
7
|
-
data: T;
|
|
8
|
-
}
|
|
9
|
-
export interface ApiError {
|
|
10
|
-
error: {
|
|
11
|
-
code: string;
|
|
12
|
-
message: string;
|
|
13
|
-
command?: string;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
export declare class HttpClient {
|
|
17
|
-
private config;
|
|
18
|
-
constructor(config: CliConfig);
|
|
19
|
-
private get headers();
|
|
20
|
-
private get base();
|
|
21
|
-
/**
|
|
22
|
-
* Attempt to refresh the JWT session. Returns true on success.
|
|
23
|
-
*/
|
|
24
|
-
private refreshSession;
|
|
25
|
-
request<T>(method: string, path: string, body?: unknown): Promise<ApiResponse<T>>;
|
|
26
|
-
listDocuments(): Promise<ApiResponse<unknown[]>>;
|
|
27
|
-
createDocument(title: string, type?: 'doc' | 'sheet' | 'slides'): Promise<ApiResponse<unknown>>;
|
|
28
|
-
getDocument(id: string): Promise<ApiResponse<unknown>>;
|
|
29
|
-
updateDocument(id: string, title: string): Promise<ApiResponse<unknown>>;
|
|
30
|
-
deleteDocument(id: string): Promise<ApiResponse<unknown>>;
|
|
31
|
-
getDocContent(docId: string): Promise<ApiResponse<Document>>;
|
|
32
|
-
putDocContent(docId: string, doc: Document): Promise<ApiResponse<Document>>;
|
|
33
|
-
getSlidesContent(docId: string): Promise<ApiResponse<SlidesDocument>>;
|
|
34
|
-
putSlidesContent(docId: string, deck: SlidesDocument): Promise<ApiResponse<SlidesDocument>>;
|
|
35
|
-
listTabs(docId: string): Promise<ApiResponse<unknown[]>>;
|
|
36
|
-
getCells(docId: string, tabId: string, range?: string): Promise<ApiResponse<unknown>>;
|
|
37
|
-
getCell(docId: string, tabId: string, sref: string): Promise<ApiResponse<unknown>>;
|
|
38
|
-
setCell(docId: string, tabId: string, sref: string, value?: string, formula?: string): Promise<ApiResponse<unknown>>;
|
|
39
|
-
deleteCell(docId: string, tabId: string, sref: string): Promise<ApiResponse<unknown>>;
|
|
40
|
-
batchCells(docId: string, tabId: string, cells: Record<string, {
|
|
41
|
-
value?: string;
|
|
42
|
-
formula?: string;
|
|
43
|
-
} | null>): Promise<ApiResponse<unknown>>;
|
|
44
|
-
listApiKeys(): Promise<{
|
|
45
|
-
ok: boolean;
|
|
46
|
-
status: number;
|
|
47
|
-
data: unknown;
|
|
48
|
-
}>;
|
|
49
|
-
createApiKey(name: string): Promise<{
|
|
50
|
-
ok: boolean;
|
|
51
|
-
status: number;
|
|
52
|
-
data: unknown;
|
|
53
|
-
}>;
|
|
54
|
-
revokeApiKey(id: string): Promise<{
|
|
55
|
-
ok: boolean;
|
|
56
|
-
status: number;
|
|
57
|
-
data: unknown;
|
|
58
|
-
}>;
|
|
59
|
-
}
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { loadSession, saveSession, decodeJwtExpiry, } from '../config/session.js';
|
|
2
|
-
export class HttpClient {
|
|
3
|
-
config;
|
|
4
|
-
constructor(config) {
|
|
5
|
-
this.config = config;
|
|
6
|
-
}
|
|
7
|
-
get headers() {
|
|
8
|
-
const h = {
|
|
9
|
-
'Content-Type': 'application/json',
|
|
10
|
-
};
|
|
11
|
-
if (this.config.authMode === 'api-key' && this.config.apiKey) {
|
|
12
|
-
h['Authorization'] = `Bearer ${this.config.apiKey}`;
|
|
13
|
-
}
|
|
14
|
-
else if (this.config.authMode === 'jwt' && this.config.accessToken) {
|
|
15
|
-
h['Authorization'] = `Bearer ${this.config.accessToken}`;
|
|
16
|
-
}
|
|
17
|
-
return h;
|
|
18
|
-
}
|
|
19
|
-
get base() {
|
|
20
|
-
const server = this.config.server.replace(/\/$/, '');
|
|
21
|
-
return `${server}/api/v1/workspaces/${this.config.workspace}`;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Attempt to refresh the JWT session. Returns true on success.
|
|
25
|
-
*/
|
|
26
|
-
async refreshSession() {
|
|
27
|
-
if (!this.config.refreshToken)
|
|
28
|
-
return false;
|
|
29
|
-
const server = this.config.server.replace(/\/$/, '');
|
|
30
|
-
const res = await fetch(`${server}/auth/refresh`, {
|
|
31
|
-
method: 'POST',
|
|
32
|
-
headers: { 'Content-Type': 'application/json' },
|
|
33
|
-
body: JSON.stringify({ refreshToken: this.config.refreshToken }),
|
|
34
|
-
});
|
|
35
|
-
if (!res.ok)
|
|
36
|
-
return false;
|
|
37
|
-
const data = (await res.json().catch(() => null));
|
|
38
|
-
if (!data?.accessToken || !data?.refreshToken)
|
|
39
|
-
return false;
|
|
40
|
-
// Update in-memory config
|
|
41
|
-
this.config.accessToken = data.accessToken;
|
|
42
|
-
this.config.refreshToken = data.refreshToken;
|
|
43
|
-
// Persist refreshed tokens to session file (if it exists).
|
|
44
|
-
// If the session file is missing the in-memory config is already
|
|
45
|
-
// updated, so the current process will keep working; the user can
|
|
46
|
-
// run `wafflebase login` to recreate the session file.
|
|
47
|
-
const session = loadSession();
|
|
48
|
-
if (session) {
|
|
49
|
-
session.accessToken = data.accessToken;
|
|
50
|
-
session.refreshToken = data.refreshToken;
|
|
51
|
-
session.expiresAt = decodeJwtExpiry(data.accessToken);
|
|
52
|
-
saveSession(session);
|
|
53
|
-
}
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
async request(method, path, body) {
|
|
57
|
-
const url = `${this.base}${path}`;
|
|
58
|
-
const res = await fetch(url, {
|
|
59
|
-
method,
|
|
60
|
-
headers: this.headers,
|
|
61
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
62
|
-
});
|
|
63
|
-
// Auto-refresh on 401 for JWT auth (one attempt only)
|
|
64
|
-
if (res.status === 401 &&
|
|
65
|
-
this.config.authMode === 'jwt' &&
|
|
66
|
-
this.config.refreshToken) {
|
|
67
|
-
const refreshed = await this.refreshSession();
|
|
68
|
-
if (refreshed) {
|
|
69
|
-
// Retry the original request with new token
|
|
70
|
-
const retryRes = await fetch(url, {
|
|
71
|
-
method,
|
|
72
|
-
headers: this.headers,
|
|
73
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
74
|
-
});
|
|
75
|
-
const retryData = (await retryRes.json().catch(() => null));
|
|
76
|
-
return { ok: retryRes.ok, status: retryRes.status, data: retryData };
|
|
77
|
-
}
|
|
78
|
-
// Refresh failed — return a clear error
|
|
79
|
-
return {
|
|
80
|
-
ok: false,
|
|
81
|
-
status: 401,
|
|
82
|
-
data: {
|
|
83
|
-
error: {
|
|
84
|
-
code: 'SESSION_EXPIRED',
|
|
85
|
-
message: 'Session expired. Run `wafflebase login`.',
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
const data = (await res.json().catch(() => null));
|
|
91
|
-
return { ok: res.ok, status: res.status, data };
|
|
92
|
-
}
|
|
93
|
-
// Documents
|
|
94
|
-
listDocuments() {
|
|
95
|
-
return this.request('GET', '/documents');
|
|
96
|
-
}
|
|
97
|
-
createDocument(title, type) {
|
|
98
|
-
const body = { title };
|
|
99
|
-
if (type)
|
|
100
|
-
body.type = type;
|
|
101
|
-
return this.request('POST', '/documents', body);
|
|
102
|
-
}
|
|
103
|
-
getDocument(id) {
|
|
104
|
-
return this.request('GET', `/documents/${id}`);
|
|
105
|
-
}
|
|
106
|
-
updateDocument(id, title) {
|
|
107
|
-
return this.request('PATCH', `/documents/${id}`, { title });
|
|
108
|
-
}
|
|
109
|
-
deleteDocument(id) {
|
|
110
|
-
return this.request('DELETE', `/documents/${id}`);
|
|
111
|
-
}
|
|
112
|
-
// Docs (word-processor) content
|
|
113
|
-
getDocContent(docId) {
|
|
114
|
-
return this.request('GET', `/documents/${docId}/content`);
|
|
115
|
-
}
|
|
116
|
-
putDocContent(docId, doc) {
|
|
117
|
-
return this.request('PUT', `/documents/${docId}/content`, doc);
|
|
118
|
-
}
|
|
119
|
-
// Slides content — same endpoint as docs; the backend dispatches on
|
|
120
|
-
// the persisted document type, picking the docs writer for `'doc'`
|
|
121
|
-
// and the slides writer for `'slides'`.
|
|
122
|
-
getSlidesContent(docId) {
|
|
123
|
-
return this.request('GET', `/documents/${docId}/content`);
|
|
124
|
-
}
|
|
125
|
-
putSlidesContent(docId, deck) {
|
|
126
|
-
return this.request('PUT', `/documents/${docId}/content`, deck);
|
|
127
|
-
}
|
|
128
|
-
// Tabs
|
|
129
|
-
listTabs(docId) {
|
|
130
|
-
return this.request('GET', `/documents/${docId}/tabs`);
|
|
131
|
-
}
|
|
132
|
-
// Cells
|
|
133
|
-
getCells(docId, tabId, range) {
|
|
134
|
-
const query = range ? `?range=${encodeURIComponent(range)}` : '';
|
|
135
|
-
return this.request('GET', `/documents/${docId}/tabs/${tabId}/cells${query}`);
|
|
136
|
-
}
|
|
137
|
-
getCell(docId, tabId, sref) {
|
|
138
|
-
return this.request('GET', `/documents/${docId}/tabs/${tabId}/cells/${sref}`);
|
|
139
|
-
}
|
|
140
|
-
setCell(docId, tabId, sref, value, formula) {
|
|
141
|
-
return this.request('PUT', `/documents/${docId}/tabs/${tabId}/cells/${sref}`, {
|
|
142
|
-
value,
|
|
143
|
-
formula,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
deleteCell(docId, tabId, sref) {
|
|
147
|
-
return this.request('DELETE', `/documents/${docId}/tabs/${tabId}/cells/${sref}`);
|
|
148
|
-
}
|
|
149
|
-
batchCells(docId, tabId, cells) {
|
|
150
|
-
return this.request('PATCH', `/documents/${docId}/tabs/${tabId}/cells`, { cells });
|
|
151
|
-
}
|
|
152
|
-
// API Keys (management endpoints use different base)
|
|
153
|
-
async listApiKeys() {
|
|
154
|
-
const server = this.config.server.replace(/\/$/, '');
|
|
155
|
-
const url = `${server}/workspaces/${this.config.workspace}/api-keys`;
|
|
156
|
-
const res = await fetch(url, { headers: this.headers });
|
|
157
|
-
const data = await res.json().catch(() => null);
|
|
158
|
-
return { ok: res.ok, status: res.status, data };
|
|
159
|
-
}
|
|
160
|
-
async createApiKey(name) {
|
|
161
|
-
const server = this.config.server.replace(/\/$/, '');
|
|
162
|
-
const url = `${server}/workspaces/${this.config.workspace}/api-keys`;
|
|
163
|
-
const res = await fetch(url, {
|
|
164
|
-
method: 'POST',
|
|
165
|
-
headers: this.headers,
|
|
166
|
-
body: JSON.stringify({ name }),
|
|
167
|
-
});
|
|
168
|
-
const data = await res.json().catch(() => null);
|
|
169
|
-
return { ok: res.ok, status: res.status, data };
|
|
170
|
-
}
|
|
171
|
-
async revokeApiKey(id) {
|
|
172
|
-
const server = this.config.server.replace(/\/$/, '');
|
|
173
|
-
const url = `${server}/workspaces/${this.config.workspace}/api-keys/${id}`;
|
|
174
|
-
const res = await fetch(url, { method: 'DELETE', headers: this.headers });
|
|
175
|
-
const data = await res.json().catch(() => null);
|
|
176
|
-
return { ok: res.ok, status: res.status, data };
|
|
177
|
-
}
|
|
178
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { getGlobalOpts, getClient } from './root.js';
|
|
2
|
-
import { output, outputError } from '../output/formatter.js';
|
|
3
|
-
export function registerApiKeysCommand(program) {
|
|
4
|
-
const apiKey = program
|
|
5
|
-
.command('api-keys')
|
|
6
|
-
.alias('api-key')
|
|
7
|
-
.description('Manage API keys');
|
|
8
|
-
apiKey
|
|
9
|
-
.command('create <name>')
|
|
10
|
-
.description('Create a new API key')
|
|
11
|
-
.action(async function (name) {
|
|
12
|
-
const opts = getGlobalOpts(this);
|
|
13
|
-
try {
|
|
14
|
-
const res = await getClient(opts).createApiKey(name);
|
|
15
|
-
if (!res.ok)
|
|
16
|
-
throw new Error(`HTTP ${res.status}`);
|
|
17
|
-
// Never suppress output — the raw key is shown only once
|
|
18
|
-
output(res.data, opts.format, false);
|
|
19
|
-
}
|
|
20
|
-
catch (e) {
|
|
21
|
-
outputError(e, opts.quiet);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
apiKey
|
|
25
|
-
.command('list')
|
|
26
|
-
.description('List API keys in workspace')
|
|
27
|
-
.action(async function () {
|
|
28
|
-
const opts = getGlobalOpts(this);
|
|
29
|
-
try {
|
|
30
|
-
const res = await getClient(opts).listApiKeys();
|
|
31
|
-
if (!res.ok)
|
|
32
|
-
throw new Error(`HTTP ${res.status}`);
|
|
33
|
-
output(res.data, opts.format, opts.quiet);
|
|
34
|
-
}
|
|
35
|
-
catch (e) {
|
|
36
|
-
outputError(e, opts.quiet);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
apiKey
|
|
40
|
-
.command('revoke <key-id>')
|
|
41
|
-
.description('Revoke an API key')
|
|
42
|
-
.action(async function (keyId) {
|
|
43
|
-
const opts = getGlobalOpts(this);
|
|
44
|
-
try {
|
|
45
|
-
const res = await getClient(opts).revokeApiKey(keyId);
|
|
46
|
-
if (!res.ok)
|
|
47
|
-
throw new Error(`HTTP ${res.status}`);
|
|
48
|
-
output(res.data, opts.format, opts.quiet);
|
|
49
|
-
}
|
|
50
|
-
catch (e) {
|
|
51
|
-
outputError(e, opts.quiet);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|
package/dist/commands/cells.d.ts
DELETED
package/dist/commands/cells.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { getGlobalOpts, getClient, getConfig } from './root.js';
|
|
2
|
-
import { output, outputError } from '../output/formatter.js';
|
|
3
|
-
import { printDryRun } from '../client/dry-run.js';
|
|
4
|
-
export function registerCellsCommand(parent) {
|
|
5
|
-
const cell = parent
|
|
6
|
-
.command('cells')
|
|
7
|
-
.alias('cell')
|
|
8
|
-
.description('Read and write cells');
|
|
9
|
-
cell
|
|
10
|
-
.command('get <doc-id> [range]')
|
|
11
|
-
.description('Get cells (default: all, or A1, or A1:C10)')
|
|
12
|
-
.option('--tab <tab-id>', 'Tab ID', 'tab-1')
|
|
13
|
-
.action(async function (docId, range) {
|
|
14
|
-
const opts = getGlobalOpts(this);
|
|
15
|
-
const { tab } = this.opts();
|
|
16
|
-
try {
|
|
17
|
-
const res = range?.includes(':')
|
|
18
|
-
? await getClient(opts).getCells(docId, tab, range)
|
|
19
|
-
: range
|
|
20
|
-
? await getClient(opts).getCell(docId, tab, range)
|
|
21
|
-
: await getClient(opts).getCells(docId, tab);
|
|
22
|
-
if (!res.ok)
|
|
23
|
-
throw new Error(`HTTP ${res.status}`);
|
|
24
|
-
output(res.data, opts.format, opts.quiet);
|
|
25
|
-
}
|
|
26
|
-
catch (e) {
|
|
27
|
-
outputError(e, opts.quiet);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
cell
|
|
31
|
-
.command('set <doc-id> <ref> <value>')
|
|
32
|
-
.description('Set a single cell value')
|
|
33
|
-
.option('--tab <tab-id>', 'Tab ID', 'tab-1')
|
|
34
|
-
.option('--formula', 'Treat value as a formula')
|
|
35
|
-
.action(async function (docId, ref, value) {
|
|
36
|
-
const opts = getGlobalOpts(this);
|
|
37
|
-
const { tab, formula } = this.opts();
|
|
38
|
-
const body = formula ? { formula: value } : { value };
|
|
39
|
-
if (opts.dryRun) {
|
|
40
|
-
printDryRun(getConfig(opts), 'PUT', `/documents/${docId}/tabs/${tab}/cells/${ref}`, body);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
try {
|
|
44
|
-
const res = await getClient(opts).setCell(docId, tab, ref, formula ? undefined : value, formula ? value : undefined);
|
|
45
|
-
if (!res.ok)
|
|
46
|
-
throw new Error(`HTTP ${res.status}`);
|
|
47
|
-
output(res.data, opts.format, opts.quiet);
|
|
48
|
-
}
|
|
49
|
-
catch (e) {
|
|
50
|
-
outputError(e, opts.quiet);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
cell
|
|
54
|
-
.command('delete <doc-id> <ref>')
|
|
55
|
-
.description('Delete a single cell')
|
|
56
|
-
.option('--tab <tab-id>', 'Tab ID', 'tab-1')
|
|
57
|
-
.action(async function (docId, ref) {
|
|
58
|
-
const opts = getGlobalOpts(this);
|
|
59
|
-
const { tab } = this.opts();
|
|
60
|
-
if (opts.dryRun) {
|
|
61
|
-
printDryRun(getConfig(opts), 'DELETE', `/documents/${docId}/tabs/${tab}/cells/${ref}`);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
const res = await getClient(opts).deleteCell(docId, tab, ref);
|
|
66
|
-
if (!res.ok)
|
|
67
|
-
throw new Error(`HTTP ${res.status}`);
|
|
68
|
-
output(res.data, opts.format, opts.quiet);
|
|
69
|
-
}
|
|
70
|
-
catch (e) {
|
|
71
|
-
outputError(e, opts.quiet);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
cell
|
|
75
|
-
.command('batch <doc-id>')
|
|
76
|
-
.description('Batch update cells (JSON from stdin or --data)')
|
|
77
|
-
.option('--tab <tab-id>', 'Tab ID', 'tab-1')
|
|
78
|
-
.option('--data <json>', 'Cell data as JSON string')
|
|
79
|
-
.action(async function (docId) {
|
|
80
|
-
const opts = getGlobalOpts(this);
|
|
81
|
-
const { tab, data: dataStr } = this.opts();
|
|
82
|
-
let cells;
|
|
83
|
-
if (dataStr) {
|
|
84
|
-
cells = JSON.parse(dataStr);
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
// Read from stdin
|
|
88
|
-
const chunks = [];
|
|
89
|
-
for await (const chunk of process.stdin) {
|
|
90
|
-
chunks.push(chunk);
|
|
91
|
-
}
|
|
92
|
-
cells = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
|
|
93
|
-
}
|
|
94
|
-
if (opts.dryRun) {
|
|
95
|
-
printDryRun(getConfig(opts), 'PATCH', `/documents/${docId}/tabs/${tab}/cells`, { cells });
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
try {
|
|
99
|
-
const res = await getClient(opts).batchCells(docId, tab, cells);
|
|
100
|
-
if (!res.ok)
|
|
101
|
-
throw new Error(`HTTP ${res.status}`);
|
|
102
|
-
output(res.data, opts.format, opts.quiet);
|
|
103
|
-
}
|
|
104
|
-
catch (e) {
|
|
105
|
-
outputError(e, opts.quiet);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
package/dist/commands/ctx.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import type { WorkspaceInfo } from '../config/session.js';
|
|
3
|
-
export declare function formatWorkspaceList(workspaces: WorkspaceInfo[], activeId: string): string;
|
|
4
|
-
export declare function findWorkspace(workspaces: WorkspaceInfo[], query: string): WorkspaceInfo | undefined;
|
|
5
|
-
export declare function registerCtxCommand(program: Command): void;
|
package/dist/commands/ctx.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { loadSession, saveSession } from '../config/session.js';
|
|
2
|
-
export function formatWorkspaceList(workspaces, activeId) {
|
|
3
|
-
return workspaces
|
|
4
|
-
.map((ws) => {
|
|
5
|
-
const marker = ws.id === activeId ? '*' : ' ';
|
|
6
|
-
return `${marker} ${ws.id.slice(0, 8)} ${ws.name}`;
|
|
7
|
-
})
|
|
8
|
-
.join('\n');
|
|
9
|
-
}
|
|
10
|
-
export function findWorkspace(workspaces, query) {
|
|
11
|
-
// Exact ID match
|
|
12
|
-
const byId = workspaces.find((ws) => ws.id === query);
|
|
13
|
-
if (byId)
|
|
14
|
-
return byId;
|
|
15
|
-
// Exact name match (case-insensitive)
|
|
16
|
-
const byName = workspaces.find((ws) => ws.name.toLowerCase() === query.toLowerCase());
|
|
17
|
-
if (byName)
|
|
18
|
-
return byName;
|
|
19
|
-
// Prefix match on ID
|
|
20
|
-
const byPrefix = workspaces.filter((ws) => ws.id.startsWith(query));
|
|
21
|
-
if (byPrefix.length === 1)
|
|
22
|
-
return byPrefix[0];
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
export function registerCtxCommand(program) {
|
|
26
|
-
const ctx = program.command('ctx').description('Workspace context switching');
|
|
27
|
-
ctx
|
|
28
|
-
.command('list')
|
|
29
|
-
.description('List workspaces')
|
|
30
|
-
.action(() => {
|
|
31
|
-
const session = loadSession();
|
|
32
|
-
if (!session) {
|
|
33
|
-
console.log('Not logged in. Run `wafflebase login`.');
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
console.log(formatWorkspaceList(session.workspaces, session.activeWorkspace));
|
|
37
|
-
});
|
|
38
|
-
ctx
|
|
39
|
-
.command('switch <name-or-id>')
|
|
40
|
-
.description('Switch active workspace')
|
|
41
|
-
.action((query) => {
|
|
42
|
-
const session = loadSession();
|
|
43
|
-
if (!session) {
|
|
44
|
-
console.error('Not logged in. Run `wafflebase login`.');
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
const ws = findWorkspace(session.workspaces, query);
|
|
48
|
-
if (!ws) {
|
|
49
|
-
console.error(`Workspace not found: ${query}`);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
session.activeWorkspace = ws.id;
|
|
53
|
-
saveSession(session);
|
|
54
|
-
console.log(`Switched to ${ws.name}.`);
|
|
55
|
-
});
|
|
56
|
-
}
|
package/dist/commands/docs.d.ts
DELETED