@proappstore/cli 2.6.61 → 2.6.63
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/billing.d.ts +1 -1
- package/dist/billing.d.ts.map +1 -1
- package/dist/billing.js +7 -4
- package/dist/billing.js.map +1 -1
- package/dist/billing.test.js +6 -1
- package/dist/billing.test.js.map +1 -1
- package/dist/data.d.ts +23 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +56 -0
- package/dist/data.js.map +1 -0
- package/dist/data.test.d.ts +2 -0
- package/dist/data.test.d.ts.map +1 -0
- package/dist/data.test.js +89 -0
- package/dist/data.test.js.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/storage.d.ts +13 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +83 -0
- package/dist/storage.js.map +1 -0
- package/dist/storage.test.d.ts +2 -0
- package/dist/storage.test.d.ts.map +1 -0
- package/dist/storage.test.js +61 -0
- package/dist/storage.test.js.map +1 -0
- package/package.json +2 -2
package/dist/billing.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export interface EntitlementRow {
|
|
|
36
36
|
}
|
|
37
37
|
/** 1234 -> "12.34 AUD". Amounts are in the smallest unit; a zero-decimal currency would need its own table, so the code is always shown. */
|
|
38
38
|
export declare function money(minor: number, currency: string | null): string;
|
|
39
|
-
export declare function formatProducts(enabled: boolean, products: BillingProductRow[]): string;
|
|
39
|
+
export declare function formatProducts(enabled: boolean, stripeEnv: string, testModeConfigured: boolean, products: BillingProductRow[]): string;
|
|
40
40
|
export declare function formatPurchases(rows: LedgerRow[], totals: {
|
|
41
41
|
currency: string;
|
|
42
42
|
gross: number;
|
package/dist/billing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IACxD,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,4IAA4I;AAC5I,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEpE;AAID,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IACxD,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,4IAA4I;AAC5I,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEpE;AAID,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAWtI;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,MAAM,CAMpJ;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,MAAM,CAIjE;AAID,eAAO,MAAM,cAAc,SAuCxB,CAAC"}
|
package/dist/billing.js
CHANGED
|
@@ -5,10 +5,13 @@ export function money(minor, currency) {
|
|
|
5
5
|
return `${(minor / 100).toFixed(2)}${currency ? ` ${currency.toUpperCase()}` : ''}`;
|
|
6
6
|
}
|
|
7
7
|
const day = (ms) => (ms ? new Date(ms).toISOString().slice(0, 10) : '-');
|
|
8
|
-
export function formatProducts(enabled, products) {
|
|
9
|
-
const lines = [
|
|
8
|
+
export function formatProducts(enabled, stripeEnv, testModeConfigured, products) {
|
|
9
|
+
const lines = [
|
|
10
|
+
`Billing is ${enabled ? 'ENABLED' : 'not enabled'} for this app${enabled ? '' : ' (a platform admin turns it on)'}.`,
|
|
11
|
+
`Stripe mode: ${stripeEnv.toUpperCase()}${stripeEnv === 'test' && !testModeConfigured ? ' (test credentials are not configured on the platform)' : ''}.`,
|
|
12
|
+
];
|
|
10
13
|
if (products.length === 0)
|
|
11
|
-
return `${lines
|
|
14
|
+
return `${lines.join('\n')}\nNo products declared.\n`;
|
|
12
15
|
for (const p of products) {
|
|
13
16
|
const term = p.interval ? `every ${p.interval.count ?? 1} ${p.interval.unit}` : 'one-off';
|
|
14
17
|
lines.push(`${p.key.padEnd(24)} ${money(p.amount, p.currency).padEnd(14)} ${p.modes.join('/').padEnd(18)} ${term}${p.active ? '' : ' (inactive)'}${p.syncError ? ` sync error: ${p.syncError}` : ''}`);
|
|
@@ -39,7 +42,7 @@ export const billingCommand = new Command('billing')
|
|
|
39
42
|
const cfg = await requireSession();
|
|
40
43
|
const appId = await resolveAppIdOrExit(opts.app);
|
|
41
44
|
const data = await ownerApi(cfg, 'GET', `/v1/apps/${appId}/billing/owner/products`, 'list billing products');
|
|
42
|
-
process.stdout.write(opts.json ? `${JSON.stringify(data, null, 2)}\n` : formatProducts(data.enabled, data.products));
|
|
45
|
+
process.stdout.write(opts.json ? `${JSON.stringify(data, null, 2)}\n` : formatProducts(data.enabled, data.stripeEnv, data.testModeConfigured, data.products));
|
|
43
46
|
}))
|
|
44
47
|
.addCommand(new Command('purchases')
|
|
45
48
|
.description('Paid purchases with gross, refunds and Stripe fees (the revenue ledger).')
|
package/dist/billing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billing.js","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAuC3E,4IAA4I;AAC5I,MAAM,UAAU,KAAK,CAAC,KAAa,EAAE,QAAuB;IAC1D,OAAO,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACtF,CAAC;AAED,MAAM,GAAG,GAAG,CAAC,EAAiB,EAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAEhG,MAAM,UAAU,cAAc,CAAC,OAAgB,EAAE,QAA6B;
|
|
1
|
+
{"version":3,"file":"billing.js","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"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"}
|
package/dist/billing.test.js
CHANGED
|
@@ -12,12 +12,17 @@ describe('pas billing', () => {
|
|
|
12
12
|
expect(money(5, null)).toBe('0.05');
|
|
13
13
|
});
|
|
14
14
|
it('says plainly when billing is off, and shows a sync error', () => {
|
|
15
|
-
const out = formatProducts(false, [{ key: 'term', name: 'Term', amount: 1000, currency: 'aud', modes: ['one_time', 'recurring'], interval: { unit: 'month', count: 3 }, active: true, syncError: 'stripe down' }]);
|
|
15
|
+
const out = formatProducts(false, 'live', true, [{ key: 'term', name: 'Term', amount: 1000, currency: 'aud', modes: ['one_time', 'recurring'], interval: { unit: 'month', count: 3 }, active: true, syncError: 'stripe down' }]);
|
|
16
16
|
expect(out).toContain('not enabled');
|
|
17
|
+
expect(out).toContain('Stripe mode: LIVE');
|
|
17
18
|
expect(out).toContain('10.00 AUD');
|
|
18
19
|
expect(out).toContain('every 3 month');
|
|
19
20
|
expect(out).toContain('sync error: stripe down');
|
|
20
21
|
});
|
|
22
|
+
it('flags test mode with no credentials configured', () => {
|
|
23
|
+
const out = formatProducts(true, 'test', false, []);
|
|
24
|
+
expect(out).toContain('Stripe mode: TEST (test credentials are not configured on the platform)');
|
|
25
|
+
});
|
|
21
26
|
it('shows refunds, a pending fee, net and totals per purchase', () => {
|
|
22
27
|
const row = { purchaseId: 'abcdef123456', product: 'term', buyerUserId: 'gh:2', subjects: ['kid-a', 'kid-b'], status: 'paid', createdAt: Date.UTC(2026, 9, 1), currency: 'aud', gross: 2000, refunded: 500, fee: null, net: 1500 };
|
|
23
28
|
const out = formatPurchases([row, { ...row, purchaseId: 'ffffffff0000', fee: 88, net: 1412 }], [{ currency: 'aud', gross: 4000, refunded: 1000, fee: 88, net: 2912 }]);
|
package/dist/billing.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billing.test.js","sourceRoot":"","sources":["../src/billing.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1G,0HAA0H;AAE1H,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;QAC/G,KAAK,MAAM,CAAC,IAAI,cAAc,CAAC,QAAQ;YAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACnG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"billing.test.js","sourceRoot":"","sources":["../src/billing.test.ts"],"names":[],"mappings":"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"}
|
package/dist/data.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* `pas data import <dir>` (#515): owner bulk import of existing data (a
|
|
4
|
+
* Firebase port above all) into one app's D1. One file per table —
|
|
5
|
+
* `<table>.json` (a JSON array of row objects) or `<table>.jsonl` (one row
|
|
6
|
+
* object per line) — posted to `POST /v1/apps/:appId/data/import`, which
|
|
7
|
+
* validates every row's columns against the app's LIVE schema before writing
|
|
8
|
+
* anything, and is safe to re-run (each row is an upsert keyed on the table's
|
|
9
|
+
* own primary key). See skills/proappstore-data-migrations-actions/references
|
|
10
|
+
* for the documented format.
|
|
11
|
+
*/
|
|
12
|
+
export type ImportRow = Record<string, unknown>;
|
|
13
|
+
/** One table's rows from `<table>.json` (a JSON array) or `<table>.jsonl` (one JSON object per line); blank lines are skipped. */
|
|
14
|
+
export declare function readTableFile(path: string): Promise<ImportRow[]>;
|
|
15
|
+
/** Every `<table>.json` / `<table>.jsonl` in `dir`, keyed by table name. Refuses a table named by both extensions at once — ambiguous which wins. */
|
|
16
|
+
export declare function readImportDir(dir: string): Promise<Record<string, ImportRow[]>>;
|
|
17
|
+
export declare function importData(opts: {
|
|
18
|
+
dir: string;
|
|
19
|
+
app: string | undefined;
|
|
20
|
+
dryRun?: boolean | undefined;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
export declare const dataCommand: Command;
|
|
23
|
+
//# sourceMappingURL=data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;;;;;;;;GASG;AAEH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAMhD,kIAAkI;AAClI,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAQtE;AAED,qJAAqJ;AACrJ,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAYrF;AAOD,wBAAsB,UAAU,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAa5H;AAED,eAAO,MAAM,WAAW,SASrB,CAAC"}
|
package/dist/data.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { extname, join } from 'node:path';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { ownerApi, requireSession, resolveAppIdOrExit } from './secret.js';
|
|
5
|
+
function tableNameOf(file) {
|
|
6
|
+
return file.slice(0, file.length - extname(file).length);
|
|
7
|
+
}
|
|
8
|
+
/** One table's rows from `<table>.json` (a JSON array) or `<table>.jsonl` (one JSON object per line); blank lines are skipped. */
|
|
9
|
+
export async function readTableFile(path) {
|
|
10
|
+
const raw = await readFile(path, 'utf8');
|
|
11
|
+
if (path.endsWith('.jsonl')) {
|
|
12
|
+
return raw.split('\n').map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
|
|
13
|
+
}
|
|
14
|
+
const parsed = JSON.parse(raw);
|
|
15
|
+
if (!Array.isArray(parsed))
|
|
16
|
+
throw new Error(`${path}: a .json import file must be an array of row objects`);
|
|
17
|
+
return parsed;
|
|
18
|
+
}
|
|
19
|
+
/** Every `<table>.json` / `<table>.jsonl` in `dir`, keyed by table name. Refuses a table named by both extensions at once — ambiguous which wins. */
|
|
20
|
+
export async function readImportDir(dir) {
|
|
21
|
+
const files = (await readdir(dir)).filter((f) => f.endsWith('.json') || f.endsWith('.jsonl'));
|
|
22
|
+
if (files.length === 0)
|
|
23
|
+
throw new Error(`${dir}: no .json or .jsonl files found`);
|
|
24
|
+
const byTable = new Map();
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
const table = tableNameOf(file);
|
|
27
|
+
if (byTable.has(table))
|
|
28
|
+
throw new Error(`"${table}" has both a .json and a .jsonl file in ${dir} — keep one`);
|
|
29
|
+
byTable.set(table, file);
|
|
30
|
+
}
|
|
31
|
+
const tables = {};
|
|
32
|
+
for (const [table, file] of byTable)
|
|
33
|
+
tables[table] = await readTableFile(join(dir, file));
|
|
34
|
+
return tables;
|
|
35
|
+
}
|
|
36
|
+
export async function importData(opts) {
|
|
37
|
+
const cfg = await requireSession();
|
|
38
|
+
const appId = await resolveAppIdOrExit(opts.app);
|
|
39
|
+
const tables = await readImportDir(opts.dir);
|
|
40
|
+
const summary = await ownerApi(cfg, 'POST', `/v1/apps/${appId}/data/import`, 'import data', { dryRun: opts.dryRun === true, tables });
|
|
41
|
+
const verb = summary.dryRun ? 'would import' : 'imported';
|
|
42
|
+
for (const [table, { rows }] of Object.entries(summary.tables)) {
|
|
43
|
+
process.stdout.write(`${verb} ${rows} row(s) into "${table}"\n`);
|
|
44
|
+
}
|
|
45
|
+
if (summary.dryRun)
|
|
46
|
+
process.stdout.write('dry run — nothing was written\n');
|
|
47
|
+
}
|
|
48
|
+
export const dataCommand = new Command('data')
|
|
49
|
+
.description('Owner bulk import of existing data into an app\'s D1.')
|
|
50
|
+
.addCommand(new Command('import')
|
|
51
|
+
.description('Import <table>.json / <table>.jsonl files from a directory, one per table. Idempotent: safe to re-run.')
|
|
52
|
+
.argument('<dir>', 'directory of <table>.json / <table>.jsonl files')
|
|
53
|
+
.option('--app <id>', 'app id (defaults to package.json name in cwd)')
|
|
54
|
+
.option('--dry-run', 'validate and report row counts; write nothing')
|
|
55
|
+
.action((dir, opts) => importData({ dir, app: opts.app, dryRun: opts.dryRun })));
|
|
56
|
+
//# sourceMappingURL=data.js.map
|
package/dist/data.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.js","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.test.d.ts","sourceRoot":"","sources":["../src/data.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
// #515: `pas data import <dir>` posts one table per <table>.json / <table>.jsonl
|
|
6
|
+
// file to the owner bulk-import route.
|
|
7
|
+
vi.mock('./lib/config.js', () => ({
|
|
8
|
+
readConfig: async () => ({ apiBase: 'https://api.test', session: { token: 'tok' } }),
|
|
9
|
+
}));
|
|
10
|
+
const { importData, readImportDir, readTableFile } = await import('./data.js');
|
|
11
|
+
let dir;
|
|
12
|
+
let calls;
|
|
13
|
+
let response;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
dir = mkdtempSync(join(tmpdir(), 'pas-data-import-'));
|
|
16
|
+
calls = [];
|
|
17
|
+
response = { dryRun: false, tables: {} };
|
|
18
|
+
vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
19
|
+
vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
|
|
20
|
+
vi.spyOn(process, 'exit').mockImplementation(((code) => { throw new Error(`exit ${code}`); }));
|
|
21
|
+
vi.stubGlobal('fetch', vi.fn(async (url, init = {}) => {
|
|
22
|
+
calls.push({ url, body: String(init.body ?? '') });
|
|
23
|
+
return Response.json(response, { status: 200 });
|
|
24
|
+
}));
|
|
25
|
+
});
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
rmSync(dir, { recursive: true, force: true });
|
|
28
|
+
vi.restoreAllMocks();
|
|
29
|
+
vi.unstubAllGlobals();
|
|
30
|
+
});
|
|
31
|
+
describe('readTableFile', () => {
|
|
32
|
+
it('reads a .json file as an array of rows', async () => {
|
|
33
|
+
const file = join(dir, 'tasks.json');
|
|
34
|
+
writeFileSync(file, JSON.stringify([{ id: '1' }, { id: '2' }]));
|
|
35
|
+
expect(await readTableFile(file)).toEqual([{ id: '1' }, { id: '2' }]);
|
|
36
|
+
});
|
|
37
|
+
it('reads a .jsonl file, one row per line, skipping blank lines', async () => {
|
|
38
|
+
const file = join(dir, 'tasks.jsonl');
|
|
39
|
+
writeFileSync(file, '{"id":"1"}\n\n{"id":"2"}\n');
|
|
40
|
+
expect(await readTableFile(file)).toEqual([{ id: '1' }, { id: '2' }]);
|
|
41
|
+
});
|
|
42
|
+
it('refuses a .json file that is not an array', async () => {
|
|
43
|
+
const file = join(dir, 'tasks.json');
|
|
44
|
+
writeFileSync(file, JSON.stringify({ id: '1' }));
|
|
45
|
+
await expect(readTableFile(file)).rejects.toThrow('must be an array of row objects');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe('readImportDir', () => {
|
|
49
|
+
it('reads every table file in the directory, keyed by table name', async () => {
|
|
50
|
+
writeFileSync(join(dir, 'tasks.json'), JSON.stringify([{ id: '1' }]));
|
|
51
|
+
writeFileSync(join(dir, 'users.jsonl'), '{"id":"u1"}\n');
|
|
52
|
+
expect(await readImportDir(dir)).toEqual({ tasks: [{ id: '1' }], users: [{ id: 'u1' }] });
|
|
53
|
+
});
|
|
54
|
+
it('refuses an empty directory', async () => {
|
|
55
|
+
await expect(readImportDir(dir)).rejects.toThrow('no .json or .jsonl files found');
|
|
56
|
+
});
|
|
57
|
+
it('refuses a table with both a .json and a .jsonl file', async () => {
|
|
58
|
+
writeFileSync(join(dir, 'tasks.json'), '[]');
|
|
59
|
+
writeFileSync(join(dir, 'tasks.jsonl'), '');
|
|
60
|
+
await expect(readImportDir(dir)).rejects.toThrow('has both a .json and a .jsonl file');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe('importData', () => {
|
|
64
|
+
it('posts { dryRun, tables } to the import route and prints a per-table summary', async () => {
|
|
65
|
+
writeFileSync(join(dir, 'tasks.json'), JSON.stringify([{ id: '1', title: 'a' }]));
|
|
66
|
+
response = { dryRun: false, tables: { tasks: { rows: 1 } } };
|
|
67
|
+
await importData({ dir, app: 'test-app' });
|
|
68
|
+
expect(calls).toHaveLength(1);
|
|
69
|
+
expect(calls[0].url).toBe('https://api.test/v1/apps/test-app/data/import');
|
|
70
|
+
expect(JSON.parse(calls[0].body)).toEqual({ dryRun: false, tables: { tasks: [{ id: '1', title: 'a' }] } });
|
|
71
|
+
expect(process.stdout.write).toHaveBeenCalledWith('imported 1 row(s) into "tasks"\n');
|
|
72
|
+
});
|
|
73
|
+
it('a --dry-run sends dryRun: true and reports without claiming a write', async () => {
|
|
74
|
+
writeFileSync(join(dir, 'tasks.json'), JSON.stringify([{ id: '1' }]));
|
|
75
|
+
response = { dryRun: true, tables: { tasks: { rows: 1 } } };
|
|
76
|
+
await importData({ dir, app: 'test-app', dryRun: true });
|
|
77
|
+
expect(JSON.parse(calls[0].body)).toMatchObject({ dryRun: true });
|
|
78
|
+
expect(process.stdout.write).toHaveBeenCalledWith('would import 1 row(s) into "tasks"\n');
|
|
79
|
+
expect(process.stdout.write).toHaveBeenCalledWith('dry run — nothing was written\n');
|
|
80
|
+
});
|
|
81
|
+
it('exits with the server error on a schema mismatch refusal', async () => {
|
|
82
|
+
writeFileSync(join(dir, 'ghosts.json'), JSON.stringify([{ id: '1' }]));
|
|
83
|
+
response = { error: 'schema mismatch', mismatches: ['table "ghosts" does not exist'] };
|
|
84
|
+
vi.mocked(fetch).mockImplementationOnce(async () => Response.json(response, { status: 400 }));
|
|
85
|
+
await expect(importData({ dir, app: 'test-app' })).rejects.toThrow('exit 1');
|
|
86
|
+
expect(process.stderr.write).toHaveBeenCalledWith(expect.stringContaining('schema mismatch'));
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=data.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.test.js","sourceRoot":"","sources":["../src/data.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,8 @@ import { permissionsCommand } from './permissions.js';
|
|
|
24
24
|
import { brandCommand } from './brand.js';
|
|
25
25
|
import { migrateCommand } from './migrate-tailwind-tokens.js';
|
|
26
26
|
import { migrationsCommand } from './migrations-test.js';
|
|
27
|
+
import { dataCommand } from './data.js';
|
|
28
|
+
import { storageCommand } from './storage.js';
|
|
27
29
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
28
30
|
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
29
31
|
const program = new Command();
|
|
@@ -76,6 +78,8 @@ program.addCommand(permissionsCommand);
|
|
|
76
78
|
program.addCommand(migrateCommand);
|
|
77
79
|
program.addCommand(migrationsCommand);
|
|
78
80
|
program.addCommand(brandCommand);
|
|
81
|
+
program.addCommand(dataCommand);
|
|
82
|
+
program.addCommand(storageCommand);
|
|
79
83
|
program.parseAsync().catch((err) => {
|
|
80
84
|
const msg = err instanceof Error ? err.message : String(err);
|
|
81
85
|
process.stderr.write(`pas: ${msg}\n`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export interface StorageImportEntry {
|
|
3
|
+
path: string;
|
|
4
|
+
key: string;
|
|
5
|
+
size: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function importStorage(opts: {
|
|
8
|
+
dir: string;
|
|
9
|
+
app: string | undefined;
|
|
10
|
+
prefix?: string | undefined;
|
|
11
|
+
}): Promise<StorageImportEntry[]>;
|
|
12
|
+
export declare const storageCommand: Command;
|
|
13
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyCpC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAqB9I;AAYD,eAAO,MAAM,cAAc,SAUxB,CAAC"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
+
import { extname, join, relative, sep } from 'node:path';
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { bearer, dieFromHttp, requireSession, resolveAppIdOrExit } from './secret.js';
|
|
5
|
+
/**
|
|
6
|
+
* `pas storage import <dir>` (#515): owner bulk upload of existing files (a
|
|
7
|
+
* Firebase port's Storage export above all) into an app's storage bucket.
|
|
8
|
+
* Uploads through the SAME route a normal upload uses — `PUT
|
|
9
|
+
* /v1/apps/:appId/storage/_public/<path>` (`routes/storage.ts`) — one file at
|
|
10
|
+
* a time, never a parallel upload path. Prints a manifest mapping each local
|
|
11
|
+
* file's relative path to its new storage key, so rows that store an old URL
|
|
12
|
+
* can be rewritten before `pas data import` (name local files after the old
|
|
13
|
+
* URL, or an id the D1 rows already carry, so the mapping is useful).
|
|
14
|
+
*/
|
|
15
|
+
const CONTENT_TYPES = {
|
|
16
|
+
'.png': 'image/png',
|
|
17
|
+
'.jpg': 'image/jpeg',
|
|
18
|
+
'.jpeg': 'image/jpeg',
|
|
19
|
+
'.webp': 'image/webp',
|
|
20
|
+
'.gif': 'image/gif',
|
|
21
|
+
'.pdf': 'application/pdf',
|
|
22
|
+
'.json': 'application/json',
|
|
23
|
+
'.csv': 'text/csv',
|
|
24
|
+
'.txt': 'text/plain',
|
|
25
|
+
};
|
|
26
|
+
function contentTypeOf(path) {
|
|
27
|
+
return CONTENT_TYPES[extname(path).toLowerCase()] ?? 'application/octet-stream';
|
|
28
|
+
}
|
|
29
|
+
/** Every file under `dir`, recursively, as POSIX-style paths relative to `dir`. */
|
|
30
|
+
async function walk(dir, root) {
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
33
|
+
const full = join(dir, entry.name);
|
|
34
|
+
if (entry.isDirectory())
|
|
35
|
+
out.push(...await walk(full, root));
|
|
36
|
+
else
|
|
37
|
+
out.push(relative(root, full).split(sep).join('/'));
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
export async function importStorage(opts) {
|
|
42
|
+
const cfg = await requireSession();
|
|
43
|
+
const appId = await resolveAppIdOrExit(opts.app);
|
|
44
|
+
const prefix = (opts.prefix ?? '').replace(/^\/+|\/+$/g, '');
|
|
45
|
+
const files = await walk(opts.dir, opts.dir);
|
|
46
|
+
if (files.length === 0)
|
|
47
|
+
throw new Error(`${opts.dir}: no files found`);
|
|
48
|
+
const manifest = [];
|
|
49
|
+
for (const relPath of files) {
|
|
50
|
+
const storagePath = `_public/${prefix ? `${prefix}/` : ''}${relPath}`;
|
|
51
|
+
const body = await readFile(join(opts.dir, relPath));
|
|
52
|
+
const res = await fetch(`${cfg.apiBase}/v1/apps/${appId}/storage/${storagePath}`, {
|
|
53
|
+
method: 'PUT',
|
|
54
|
+
headers: { ...bearer(cfg), 'Content-Type': contentTypeOf(relPath) },
|
|
55
|
+
body: new Uint8Array(body),
|
|
56
|
+
});
|
|
57
|
+
if (!res.ok)
|
|
58
|
+
await dieFromHttp(res, `upload ${relPath}`);
|
|
59
|
+
const { key } = (await res.json());
|
|
60
|
+
manifest.push({ path: relPath, key, size: body.byteLength });
|
|
61
|
+
}
|
|
62
|
+
return manifest;
|
|
63
|
+
}
|
|
64
|
+
async function runStorageImport(dir, opts) {
|
|
65
|
+
const manifest = await importStorage({ dir, app: opts.app, prefix: opts.prefix });
|
|
66
|
+
if (opts.json) {
|
|
67
|
+
process.stdout.write(`${JSON.stringify(manifest, null, 2)}\n`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const entry of manifest)
|
|
71
|
+
process.stdout.write(`${entry.path} -> ${entry.key} (${entry.size} bytes)\n`);
|
|
72
|
+
process.stdout.write(`${manifest.length} file(s) uploaded.\n`);
|
|
73
|
+
}
|
|
74
|
+
export const storageCommand = new Command('storage')
|
|
75
|
+
.description('Owner bulk upload of existing files into an app\'s storage.')
|
|
76
|
+
.addCommand(new Command('import')
|
|
77
|
+
.description('Upload every file under <dir> into storage, under _public/[prefix/]<relative path>. Prints a path -> key manifest.')
|
|
78
|
+
.argument('<dir>', 'local directory to upload, recursively')
|
|
79
|
+
.option('--app <id>', 'app id (defaults to package.json name in cwd)')
|
|
80
|
+
.option('--prefix <path>', 'key prefix under _public/ (defaults to none)')
|
|
81
|
+
.option('--json', 'Output the manifest as JSON.')
|
|
82
|
+
.action(runStorageImport));
|
|
83
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.test.d.ts","sourceRoot":"","sources":["../src/storage.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
// #515: `pas storage import <dir>` uploads every file under <dir> through the
|
|
6
|
+
// EXISTING `PUT /v1/apps/:appId/storage/*` route, one file at a time, and
|
|
7
|
+
// prints a path -> key manifest.
|
|
8
|
+
vi.mock('./lib/config.js', () => ({
|
|
9
|
+
readConfig: async () => ({ apiBase: 'https://api.test', session: { token: 'tok' } }),
|
|
10
|
+
}));
|
|
11
|
+
const { importStorage } = await import('./storage.js');
|
|
12
|
+
let dir;
|
|
13
|
+
let calls;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
dir = mkdtempSync(join(tmpdir(), 'pas-storage-import-'));
|
|
16
|
+
calls = [];
|
|
17
|
+
vi.stubGlobal('fetch', vi.fn(async (url, init = {}) => {
|
|
18
|
+
const headers = new Headers(init.headers);
|
|
19
|
+
calls.push({ url, method: init.method ?? 'GET', headers, body: new Uint8Array(init.body) });
|
|
20
|
+
const key = decodeURIComponent(new URL(url).pathname.split('/storage/')[1]);
|
|
21
|
+
return Response.json({ key, size: init.body.byteLength, contentType: headers.get('Content-Type'), url: `/v1/apps/x/storage/${key}` }, { status: 200 });
|
|
22
|
+
}));
|
|
23
|
+
});
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
rmSync(dir, { recursive: true, force: true });
|
|
26
|
+
vi.restoreAllMocks();
|
|
27
|
+
vi.unstubAllGlobals();
|
|
28
|
+
});
|
|
29
|
+
describe('importStorage', () => {
|
|
30
|
+
it('uploads every file under the directory, recursively, under _public/', async () => {
|
|
31
|
+
writeFileSync(join(dir, 'floor1.png'), 'png-bytes');
|
|
32
|
+
mkdirSync(join(dir, 'mall-a'));
|
|
33
|
+
writeFileSync(join(dir, 'mall-a', 'floor2.png'), 'png-bytes-2');
|
|
34
|
+
const manifest = await importStorage({ dir, app: 'test-app' });
|
|
35
|
+
expect(calls).toHaveLength(2);
|
|
36
|
+
expect(calls.every((c) => c.method === 'PUT')).toBe(true);
|
|
37
|
+
expect(calls.every((c) => c.headers.get('Authorization') === 'Bearer tok')).toBe(true);
|
|
38
|
+
expect(manifest.sort((a, b) => a.path.localeCompare(b.path))).toEqual([
|
|
39
|
+
{ path: 'floor1.png', key: '_public/floor1.png', size: 9 },
|
|
40
|
+
{ path: 'mall-a/floor2.png', key: '_public/mall-a/floor2.png', size: 11 },
|
|
41
|
+
]);
|
|
42
|
+
});
|
|
43
|
+
it('applies --prefix under _public/', async () => {
|
|
44
|
+
writeFileSync(join(dir, 'a.png'), 'x');
|
|
45
|
+
const manifest = await importStorage({ dir, app: 'test-app', prefix: 'mallguide' });
|
|
46
|
+
expect(manifest[0].key).toBe('_public/mallguide/a.png');
|
|
47
|
+
expect(calls[0].url).toContain('/storage/_public/mallguide/a.png');
|
|
48
|
+
});
|
|
49
|
+
it('sets Content-Type from the file extension', async () => {
|
|
50
|
+
writeFileSync(join(dir, 'a.png'), 'x');
|
|
51
|
+
writeFileSync(join(dir, 'b.bin'), 'x');
|
|
52
|
+
await importStorage({ dir, app: 'test-app' });
|
|
53
|
+
const byUrl = Object.fromEntries(calls.map((c) => [c.url, c.headers.get('Content-Type')]));
|
|
54
|
+
expect(byUrl[Object.keys(byUrl).find((u) => u.endsWith('a.png'))]).toBe('image/png');
|
|
55
|
+
expect(byUrl[Object.keys(byUrl).find((u) => u.endsWith('b.bin'))]).toBe('application/octet-stream');
|
|
56
|
+
});
|
|
57
|
+
it('refuses an empty directory', async () => {
|
|
58
|
+
await expect(importStorage({ dir, app: 'test-app' })).rejects.toThrow('no files found');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=storage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.test.js","sourceRoot":"","sources":["../src/storage.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proappstore/cli",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.63",
|
|
4
4
|
"description": "pas — CLI for publishing paid apps to proappstore.online",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"commander": "^12.1.0",
|
|
25
|
-
"@proappstore/compliance": "0.2.
|
|
25
|
+
"@proappstore/compliance": "0.2.31"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.0.0",
|