@pushto/cli 0.4.9 → 0.4.10

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 (70) hide show
  1. package/dist/commands/__tests__/auth-add.test.d.ts +2 -0
  2. package/dist/commands/__tests__/auth-add.test.d.ts.map +1 -0
  3. package/dist/commands/__tests__/auth-add.test.js +27 -0
  4. package/dist/commands/__tests__/auth-add.test.js.map +1 -0
  5. package/dist/commands/__tests__/deploy-target.test.d.ts +2 -0
  6. package/dist/commands/__tests__/deploy-target.test.d.ts.map +1 -0
  7. package/dist/commands/__tests__/deploy-target.test.js +43 -0
  8. package/dist/commands/__tests__/deploy-target.test.js.map +1 -0
  9. package/dist/commands/__tests__/headless-smoke.test.js +35 -1
  10. package/dist/commands/__tests__/headless-smoke.test.js.map +1 -1
  11. package/dist/commands/__tests__/upgrade-trust.test.d.ts +2 -0
  12. package/dist/commands/__tests__/upgrade-trust.test.d.ts.map +1 -0
  13. package/dist/commands/__tests__/upgrade-trust.test.js +26 -0
  14. package/dist/commands/__tests__/upgrade-trust.test.js.map +1 -0
  15. package/dist/commands/auth.d.ts +13 -1
  16. package/dist/commands/auth.d.ts.map +1 -1
  17. package/dist/commands/auth.js +100 -1
  18. package/dist/commands/auth.js.map +1 -1
  19. package/dist/commands/deploy.d.ts +27 -0
  20. package/dist/commands/deploy.d.ts.map +1 -1
  21. package/dist/commands/deploy.js +66 -8
  22. package/dist/commands/deploy.js.map +1 -1
  23. package/dist/commands/init.d.ts.map +1 -1
  24. package/dist/commands/init.js +20 -45
  25. package/dist/commands/init.js.map +1 -1
  26. package/dist/commands/link.d.ts +10 -0
  27. package/dist/commands/link.d.ts.map +1 -0
  28. package/dist/commands/link.js +78 -0
  29. package/dist/commands/link.js.map +1 -0
  30. package/dist/commands/preview.d.ts.map +1 -1
  31. package/dist/commands/preview.js +7 -4
  32. package/dist/commands/preview.js.map +1 -1
  33. package/dist/commands/upgrade.d.ts +2 -0
  34. package/dist/commands/upgrade.d.ts.map +1 -1
  35. package/dist/commands/upgrade.js +52 -1
  36. package/dist/commands/upgrade.js.map +1 -1
  37. package/dist/commands/use.d.ts.map +1 -1
  38. package/dist/commands/use.js +2 -1
  39. package/dist/commands/use.js.map +1 -1
  40. package/dist/index.js +12 -3
  41. package/dist/index.js.map +1 -1
  42. package/dist/lib/__tests__/resolve-slug.test.d.ts +2 -0
  43. package/dist/lib/__tests__/resolve-slug.test.d.ts.map +1 -0
  44. package/dist/lib/__tests__/resolve-slug.test.js +54 -0
  45. package/dist/lib/__tests__/resolve-slug.test.js.map +1 -0
  46. package/dist/lib/__tests__/snippet-insert.test.d.ts +2 -0
  47. package/dist/lib/__tests__/snippet-insert.test.d.ts.map +1 -0
  48. package/dist/lib/__tests__/snippet-insert.test.js +69 -0
  49. package/dist/lib/__tests__/snippet-insert.test.js.map +1 -0
  50. package/dist/lib/create-project.d.ts +19 -0
  51. package/dist/lib/create-project.d.ts.map +1 -0
  52. package/dist/lib/create-project.js +51 -0
  53. package/dist/lib/create-project.js.map +1 -0
  54. package/dist/lib/project-name.d.ts +6 -0
  55. package/dist/lib/project-name.d.ts.map +1 -0
  56. package/dist/lib/project-name.js +10 -0
  57. package/dist/lib/project-name.js.map +1 -0
  58. package/dist/lib/resolve-slug.d.ts +13 -3
  59. package/dist/lib/resolve-slug.d.ts.map +1 -1
  60. package/dist/lib/resolve-slug.js +21 -9
  61. package/dist/lib/resolve-slug.js.map +1 -1
  62. package/dist/lib/snippet-insert.d.ts +36 -0
  63. package/dist/lib/snippet-insert.d.ts.map +1 -0
  64. package/dist/lib/snippet-insert.js +74 -0
  65. package/dist/lib/snippet-insert.js.map +1 -0
  66. package/dist/version.d.ts +1 -1
  67. package/dist/version.d.ts.map +1 -1
  68. package/dist/version.js +3 -3
  69. package/dist/version.js.map +1 -1
  70. package/package.json +1 -1
@@ -0,0 +1,54 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ vi.mock('../config.js', () => ({
6
+ getProjectSlug: vi.fn(() => 'global-fallback'),
7
+ }));
8
+ import { readLocalSlug, resolveSlug } from '../resolve-slug.js';
9
+ /**
10
+ * PINs the split that fixes the soiaa → offload-test misdeploy (2026-07-30).
11
+ *
12
+ * The global slug is wherever the last `pushto init`/`pushto use` happened —
13
+ * any directory on the machine. Commands that upload the cwd must therefore
14
+ * resolve from the directory's own .pushto ONLY: readLocalSlug never falls
15
+ * back, while resolveSlug keeps the fallback for control commands (logs,
16
+ * status, open…), which is the behavior `pushto use` promises.
17
+ */
18
+ const tmpDir = () => fs.mkdtempSync(path.join(os.tmpdir(), 'pushto-slug-'));
19
+ const writeLink = (dir, content) => {
20
+ fs.writeFileSync(path.join(dir, '.pushto'), content);
21
+ };
22
+ describe('readLocalSlug', () => {
23
+ it('reads the slug from the directory .pushto file', () => {
24
+ const dir = tmpDir();
25
+ writeLink(dir, JSON.stringify({ slug: 'soiaa' }));
26
+ expect(readLocalSlug(dir)).toBe('soiaa');
27
+ });
28
+ it('returns undefined when the directory has no .pushto — never the global slug', () => {
29
+ const dir = tmpDir();
30
+ expect(readLocalSlug(dir)).toBeUndefined();
31
+ });
32
+ it('returns undefined on malformed .pushto JSON', () => {
33
+ const dir = tmpDir();
34
+ writeLink(dir, '{not json');
35
+ expect(readLocalSlug(dir)).toBeUndefined();
36
+ });
37
+ it('rejects slugs that fail the safe-slug shape', () => {
38
+ const dir = tmpDir();
39
+ writeLink(dir, JSON.stringify({ slug: '../../etc/passwd' }));
40
+ expect(readLocalSlug(dir)).toBeUndefined();
41
+ });
42
+ });
43
+ describe('resolveSlug (control commands)', () => {
44
+ it('prefers the directory link over the global slug', () => {
45
+ const dir = tmpDir();
46
+ writeLink(dir, JSON.stringify({ slug: 'linked-here' }));
47
+ expect(resolveSlug(dir)).toBe('linked-here');
48
+ });
49
+ it('still falls back to the global slug for unlinked directories', () => {
50
+ const dir = tmpDir();
51
+ expect(resolveSlug(dir)).toBe('global-fallback');
52
+ });
53
+ });
54
+ //# sourceMappingURL=resolve-slug.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-slug.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/resolve-slug.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=snippet-insert.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snippet-insert.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/snippet-insert.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mkdtempSync, writeFileSync, mkdirSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { WIDGET_SRC, authSnippet, isAlreadyWired, insertBeforeBody, detectTarget, reactWrapperSource, } from '../snippet-insert.js';
6
+ const tmp = () => mkdtempSync(join(tmpdir(), 'pushto-auth-add-'));
7
+ describe('authSnippet', () => {
8
+ it('is exactly two lines with the real values inline', () => {
9
+ const s = authSnippet('proj_x', 'pta_abc');
10
+ expect(s.split('\n')).toHaveLength(2);
11
+ expect(s).toContain('id="pushto-auth"');
12
+ expect(s).toContain(`src="${WIDGET_SRC}"`);
13
+ expect(s).toContain('data-project="proj_x"');
14
+ expect(s).toContain('data-key="pta_abc"');
15
+ });
16
+ });
17
+ describe('insertBeforeBody', () => {
18
+ it('inserts before the LAST closing body tag, case-insensitively', () => {
19
+ const html = '<html><body><p>hi</p></BODY></html>';
20
+ const out = insertBeforeBody(html, authSnippet('p', 'k'));
21
+ expect(out).not.toBeNull();
22
+ expect(out.indexOf('pushto-auth')).toBeLessThan(out.indexOf('</BODY>'));
23
+ expect(out).toContain('<p>hi</p>');
24
+ });
25
+ it('returns null when there is no closing body tag — print, do not guess', () => {
26
+ expect(insertBeforeBody('<div>fragment</div>', 'x')).toBeNull();
27
+ });
28
+ });
29
+ describe('isAlreadyWired', () => {
30
+ it('recognizes the widget src wherever it appears', () => {
31
+ expect(isAlreadyWired(`<script src="${WIDGET_SRC}"></script>`)).toBe(true);
32
+ expect(isAlreadyWired('<html></html>')).toBe(false);
33
+ });
34
+ });
35
+ describe('detectTarget', () => {
36
+ it('prefers root index.html', () => {
37
+ const dir = tmp();
38
+ writeFileSync(join(dir, 'index.html'), '<html></html>');
39
+ expect(detectTarget(dir)).toEqual({ kind: 'html', path: join(dir, 'index.html') });
40
+ });
41
+ it('falls back to public/index.html', () => {
42
+ const dir = tmp();
43
+ mkdirSync(join(dir, 'public'));
44
+ writeFileSync(join(dir, 'public', 'index.html'), '<html></html>');
45
+ expect(detectTarget(dir)).toEqual({ kind: 'html', path: join(dir, 'public', 'index.html') });
46
+ });
47
+ it('detects react from package.json dependencies', () => {
48
+ const dir = tmp();
49
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({ dependencies: { react: '^18.0.0' } }));
50
+ expect(detectTarget(dir)).toEqual({ kind: 'react' });
51
+ });
52
+ it('returns none for an unrecognizable directory or broken package.json', () => {
53
+ const dir = tmp();
54
+ expect(detectTarget(dir)).toEqual({ kind: 'none' });
55
+ writeFileSync(join(dir, 'package.json'), '{not json');
56
+ expect(detectTarget(dir)).toEqual({ kind: 'none' });
57
+ });
58
+ });
59
+ describe('reactWrapperSource', () => {
60
+ it('bakes in the values and points at the hosted widget', () => {
61
+ const src = reactWrapperSource('proj_x', 'pta_abc');
62
+ expect(src).toContain(WIDGET_SRC);
63
+ expect(src).toContain("'proj_x'");
64
+ expect(src).toContain("'pta_abc'");
65
+ expect(src).toContain('PushtoAuth');
66
+ expect(src).toContain('<div id="pushto-auth"');
67
+ });
68
+ });
69
+ //# sourceMappingURL=snippet-insert.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snippet-insert.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/snippet-insert.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export type CreateProjectOutcome = {
2
+ ok: true;
3
+ projectId?: string;
4
+ message?: string;
5
+ } | {
6
+ ok: false;
7
+ error: string;
8
+ network: boolean;
9
+ };
10
+ /**
11
+ * Create a project on the server and link this directory to it — the shared
12
+ * spine of `pushto init` and deploy's create-on-first-push. Writes .pushto
13
+ * in cwd and stores the slug globally so control commands follow along.
14
+ */
15
+ export declare const createAndLinkProject: (slug: string, opts?: {
16
+ displayName?: string;
17
+ cwd?: string;
18
+ }) => Promise<CreateProjectOutcome>;
19
+ //# sourceMappingURL=create-project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-project.d.ts","sourceRoot":"","sources":["../../src/lib/create-project.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,OAAM;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,KAChD,OAAO,CAAC,oBAAoB,CA4C9B,CAAC"}
@@ -0,0 +1,51 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { api } from './api.js';
4
+ import { safeJson } from './safe-json.js';
5
+ import { setProjectSlug } from './config.js';
6
+ /**
7
+ * Create a project on the server and link this directory to it — the shared
8
+ * spine of `pushto init` and deploy's create-on-first-push. Writes .pushto
9
+ * in cwd and stores the slug globally so control commands follow along.
10
+ */
11
+ export const createAndLinkProject = async (slug, opts = {}) => {
12
+ const cwd = opts.cwd ?? process.cwd();
13
+ let res;
14
+ try {
15
+ res = await api('/cli/projects', {
16
+ method: 'POST',
17
+ body: JSON.stringify({ name: opts.displayName ?? slug, slug }),
18
+ });
19
+ }
20
+ catch (err) {
21
+ const msg = err instanceof Error ? err.message : '';
22
+ const isNetwork = /fetch|enotfound|econnrefused|timeout|abort|network/i.test(msg);
23
+ return {
24
+ ok: false,
25
+ network: isNetwork,
26
+ error: isNetwork
27
+ ? 'could not reach pushto.host. check your internet.'
28
+ : `couldn't create the project: ${msg || 'unknown error'}`,
29
+ };
30
+ }
31
+ const data = await safeJson(res);
32
+ if (!res.ok) {
33
+ return { ok: false, network: false, error: data.error ?? 'something went wrong.' };
34
+ }
35
+ try {
36
+ fs.writeFileSync(path.join(cwd, '.pushto'), `${JSON.stringify({ slug, projectId: data.project?.id }, null, 2)}\n`);
37
+ }
38
+ catch (err) {
39
+ // The project exists server-side at this point — say so, and hand the
40
+ // user the command that finishes the half-done link.
41
+ const msg = err instanceof Error ? err.message : 'unknown error';
42
+ return {
43
+ ok: false,
44
+ network: false,
45
+ error: `${slug} was created, but linking this directory failed: ${msg}. finish with pushto link ${slug}.`,
46
+ };
47
+ }
48
+ setProjectSlug(slug);
49
+ return { ok: true, projectId: data.project?.id, message: data.message };
50
+ };
51
+ //# sourceMappingURL=create-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-project.js","sourceRoot":"","sources":["../../src/lib/create-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAM7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EACvC,IAAY,EACZ,OAA+C,EAAE,EAClB,EAAE;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEtC,IAAI,GAAoC,CAAC;IACzC,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,GAAG,CAAC,eAAe,EAAE;YAC/B,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,EAAE,IAAI,EAAE,CAAC;SAC/D,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,MAAM,SAAS,GAAG,qDAAqD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClF,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,SAAS;YAClB,KAAK,EAAE,SAAS;gBACd,CAAC,CAAC,mDAAmD;gBACrD,CAAC,CAAC,gCAAgC,GAAG,IAAI,eAAe,EAAE;SAC7D,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAiE,GAAG,CAAC,CAAC;IACjG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,uBAAuB,EAAE,CAAC;IACrF,CAAC;IAED,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EACzB,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACtE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,sEAAsE;QACtE,qDAAqD;QACrD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACjE,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,GAAG,IAAI,oDAAoD,GAAG,6BAA6B,IAAI,GAAG;SAC1G,CAAC;IACJ,CAAC;IAED,cAAc,CAAC,IAAI,CAAC,CAAC;IACrB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;AAC1E,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** The naming rules `pushto init` has always applied, shared with deploy's
2
+ * create-on-first-push path so a directory name and an explicit name can
3
+ * never slugify differently. */
4
+ export declare const slugifyProjectName: (name: string) => string;
5
+ export declare const MIN_SLUG_LENGTH = 3;
6
+ //# sourceMappingURL=project-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-name.d.ts","sourceRoot":"","sources":["../../src/lib/project-name.ts"],"names":[],"mappings":"AAAA;;iCAEiC;AACjC,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAKxB,CAAC;AAE3B,eAAO,MAAM,eAAe,IAAI,CAAC"}
@@ -0,0 +1,10 @@
1
+ /** The naming rules `pushto init` has always applied, shared with deploy's
2
+ * create-on-first-push path so a directory name and an explicit name can
3
+ * never slugify differently. */
4
+ export const slugifyProjectName = (name) => name
5
+ .toLowerCase()
6
+ .replace(/[^a-z0-9-]/g, '-')
7
+ .replace(/-+/g, '-')
8
+ .replace(/^-|-$/g, '');
9
+ export const MIN_SLUG_LENGTH = 3;
10
+ //# sourceMappingURL=project-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-name.js","sourceRoot":"","sources":["../../src/lib/project-name.ts"],"names":[],"mappings":"AAAA;;iCAEiC;AACjC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAU,EAAE,CACzD,IAAI;KACD,WAAW,EAAE;KACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;KAC3B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;KACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAE3B,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC"}
@@ -1,7 +1,17 @@
1
1
  /**
2
- * Resolve the project slug from:
2
+ * The slug linked to this directory by its .pushto file, or undefined.
3
+ *
4
+ * Commands that UPLOAD the directory (deploy, preview) must use this and
5
+ * never resolveSlug: the global slug points wherever init/use last ran —
6
+ * any directory on the machine — and following it shipped a brand-new
7
+ * project's files into an unrelated old project (soiaa → offload-test,
8
+ * 2026-07-30).
9
+ */
10
+ export declare const readLocalSlug: (cwd?: string) => string | undefined;
11
+ /**
12
+ * Resolve the project slug for CONTROL commands (logs, status, open, env…):
3
13
  * 1. .pushto file in the current directory
4
- * 2. Global config (last `pushto init`)
14
+ * 2. Global config (last `pushto init` / `pushto use`)
5
15
  */
6
- export declare const resolveSlug: () => string | undefined;
16
+ export declare const resolveSlug: (cwd?: string) => string | undefined;
7
17
  //# sourceMappingURL=resolve-slug.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-slug.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-slug.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,eAAO,MAAM,WAAW,QAAO,MAAM,GAAG,SAiBvC,CAAC"}
1
+ {"version":3,"file":"resolve-slug.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-slug.ts"],"names":[],"mappings":"AASA;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAI,MAAK,MAAsB,KAAG,MAAM,GAAG,SAWpE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,MAAK,MAAsB,KAAG,MAAM,GAAG,SAOlE,CAAC"}
@@ -5,24 +5,36 @@ import { getProjectSlug } from './config.js';
5
5
  const SAFE_SLUG_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
6
6
  const isValidSlug = (slug) => slug.length >= 2 && slug.length <= 63 && SAFE_SLUG_RE.test(slug);
7
7
  /**
8
- * Resolve the project slug from:
9
- * 1. .pushto file in the current directory
10
- * 2. Global config (last `pushto init`)
8
+ * The slug linked to this directory by its .pushto file, or undefined.
9
+ *
10
+ * Commands that UPLOAD the directory (deploy, preview) must use this and
11
+ * never resolveSlug: the global slug points wherever init/use last ran —
12
+ * any directory on the machine — and following it shipped a brand-new
13
+ * project's files into an unrelated old project (soiaa → offload-test,
14
+ * 2026-07-30).
11
15
  */
12
- export const resolveSlug = () => {
13
- // Check for .pushto file in cwd
14
- const pushtoFile = path.join(process.cwd(), '.pushto');
16
+ export const readLocalSlug = (cwd = process.cwd()) => {
15
17
  try {
16
- const content = fs.readFileSync(pushtoFile, 'utf-8');
18
+ const content = fs.readFileSync(path.join(cwd, '.pushto'), 'utf-8');
17
19
  const parsed = JSON.parse(content);
18
20
  if (typeof parsed.slug === 'string' && isValidSlug(parsed.slug)) {
19
21
  return parsed.slug;
20
22
  }
21
23
  }
22
24
  catch {
23
- // No .pushto file or invalid JSON — fall through
25
+ // No .pushto file or invalid JSON — this directory simply isn't linked
24
26
  }
25
- // Fall back to global config
27
+ return undefined;
28
+ };
29
+ /**
30
+ * Resolve the project slug for CONTROL commands (logs, status, open, env…):
31
+ * 1. .pushto file in the current directory
32
+ * 2. Global config (last `pushto init` / `pushto use`)
33
+ */
34
+ export const resolveSlug = (cwd = process.cwd()) => {
35
+ const local = readLocalSlug(cwd);
36
+ if (local)
37
+ return local;
26
38
  const globalSlug = getProjectSlug();
27
39
  if (globalSlug && isValidSlug(globalSlug))
28
40
  return globalSlug;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-slug.js","sourceRoot":"","sources":["../../src/lib/resolve-slug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,iFAAiF;AACjF,MAAM,YAAY,GAAG,8BAA8B,CAAC;AACpD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE,CAC5C,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEnE;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,GAAuB,EAAE;IAClD,gCAAgC;IAChC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAChE,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,iDAAiD;IACnD,CAAC;IAED,6BAA6B;IAC7B,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,IAAI,UAAU,IAAI,WAAW,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IAC7D,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
1
+ {"version":3,"file":"resolve-slug.js","sourceRoot":"","sources":["../../src/lib/resolve-slug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,iFAAiF;AACjF,MAAM,YAAY,GAAG,8BAA8B,CAAC;AACpD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE,CAC5C,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE,EAAsB,EAAE;IAC/E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAChE,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE,EAAsB,EAAE;IAC7E,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,IAAI,UAAU,IAAI,WAAW,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IAC7D,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Everything `pushto auth add` needs to put the widget in a project,
3
+ * as pure functions the tests can hold still.
4
+ *
5
+ * The snippet always points at the canonical host — it runs on the
6
+ * user's site, not against whatever apiUrl this CLI happens to target.
7
+ */
8
+ export declare const WIDGET_SRC = "https://pushto.host/api/auth/widget.js";
9
+ export declare const authSnippet: (projectId: string, apiKey: string) => string;
10
+ export declare const isAlreadyWired: (source: string) => boolean;
11
+ /** Insert before the LAST </body> (case-insensitive). Null = no anchor: print, don't guess. */
12
+ export declare const insertBeforeBody: (html: string, snippet: string) => string | null;
13
+ export type SnippetTarget = {
14
+ kind: 'html';
15
+ path: string;
16
+ } | {
17
+ kind: 'react';
18
+ } | {
19
+ kind: 'none';
20
+ };
21
+ /**
22
+ * html first, deliberately: a vite+react app has BOTH a root index.html
23
+ * and a react dependency, and the root index.html is its real entry —
24
+ * inserting there puts the widget on the served page without touching
25
+ * any component.
26
+ */
27
+ export declare const detectTarget: (dir: string) => SnippetTarget;
28
+ /**
29
+ * Kept in sync BY HAND with the dashboard's react snippet
30
+ * (apps/web/.../auth/page.tsx reactSnippet). Not imported from
31
+ * packages/shared: the CLI's NodeNext resolution and the shared barrel
32
+ * have a standing standoff (2026-07-25), and 20 lines is cheaper than
33
+ * reopening it.
34
+ */
35
+ export declare const reactWrapperSource: (projectId: string, apiKey: string) => string;
36
+ //# sourceMappingURL=snippet-insert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snippet-insert.d.ts","sourceRoot":"","sources":["../../src/lib/snippet-insert.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AAEH,eAAO,MAAM,UAAU,2CAA2C,CAAC;AAEnE,eAAO,MAAM,WAAW,GAAI,WAAW,MAAM,EAAE,QAAQ,MAAM,KAAG,MACwD,CAAC;AAEzH,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,KAAG,OAAsC,CAAC;AAEvF,+FAA+F;AAC/F,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,MAAM,GAAG,IAIzE,CAAC;AAEF,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,aAgB1C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,EAAE,QAAQ,MAAM,KAAG,MAuBtE,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * Everything `pushto auth add` needs to put the widget in a project,
5
+ * as pure functions the tests can hold still.
6
+ *
7
+ * The snippet always points at the canonical host — it runs on the
8
+ * user's site, not against whatever apiUrl this CLI happens to target.
9
+ */
10
+ export const WIDGET_SRC = 'https://pushto.host/api/auth/widget.js';
11
+ export const authSnippet = (projectId, apiKey) => `<div id="pushto-auth"></div>\n<script src="${WIDGET_SRC}" data-project="${projectId}" data-key="${apiKey}"></script>`;
12
+ export const isAlreadyWired = (source) => source.includes(WIDGET_SRC);
13
+ /** Insert before the LAST </body> (case-insensitive). Null = no anchor: print, don't guess. */
14
+ export const insertBeforeBody = (html, snippet) => {
15
+ const idx = html.toLowerCase().lastIndexOf('</body>');
16
+ if (idx === -1)
17
+ return null;
18
+ return `${html.slice(0, idx)} ${snippet}\n${html.slice(idx)}`;
19
+ };
20
+ /**
21
+ * html first, deliberately: a vite+react app has BOTH a root index.html
22
+ * and a react dependency, and the root index.html is its real entry —
23
+ * inserting there puts the widget on the served page without touching
24
+ * any component.
25
+ */
26
+ export const detectTarget = (dir) => {
27
+ for (const candidate of [join(dir, 'index.html'), join(dir, 'public', 'index.html')]) {
28
+ if (existsSync(candidate))
29
+ return { kind: 'html', path: candidate };
30
+ }
31
+ const pkgPath = join(dir, 'package.json');
32
+ if (existsSync(pkgPath)) {
33
+ try {
34
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
35
+ if (pkg.dependencies?.react)
36
+ return { kind: 'react' };
37
+ }
38
+ catch {
39
+ // broken package.json — fall through to none; add prints instead
40
+ }
41
+ }
42
+ return { kind: 'none' };
43
+ };
44
+ /**
45
+ * Kept in sync BY HAND with the dashboard's react snippet
46
+ * (apps/web/.../auth/page.tsx reactSnippet). Not imported from
47
+ * packages/shared: the CLI's NodeNext resolution and the shared barrel
48
+ * have a standing standoff (2026-07-25), and 20 lines is cheaper than
49
+ * reopening it.
50
+ */
51
+ export const reactWrapperSource = (projectId, apiKey) => `// pushto auth — drop-in component backed by the hosted widget
52
+ import { useEffect } from 'react';
53
+
54
+ const SRC = '${WIDGET_SRC}';
55
+ const PROJECT = '${projectId}';
56
+ const KEY = '${apiKey}';
57
+
58
+ export function PushtoAuth() {
59
+ useEffect(() => {
60
+ if (document.getElementById('pushto-auth-loader')) return;
61
+ const s = document.createElement('script');
62
+ s.id = 'pushto-auth-loader';
63
+ s.src = SRC;
64
+ s.setAttribute('data-project', PROJECT);
65
+ s.setAttribute('data-key', KEY);
66
+ document.body.appendChild(s);
67
+ }, []);
68
+ return <div id="pushto-auth" />;
69
+ }
70
+
71
+ // once loaded, session helpers live on window.pushtoAuth:
72
+ // .getUser() .login(email, pw) .signup(email, pw) .logout() .onChange(cb)
73
+ `;
74
+ //# sourceMappingURL=snippet-insert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snippet-insert.js","sourceRoot":"","sources":["../../src/lib/snippet-insert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,wCAAwC,CAAC;AAEnE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,SAAiB,EAAE,MAAc,EAAU,EAAE,CACvE,8CAA8C,UAAU,mBAAmB,SAAS,eAAe,MAAM,aAAa,CAAC;AAEzH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAc,EAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAEvF,+FAA+F;AAC/F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAE,OAAe,EAAiB,EAAE;IAC/E,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IACtD,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,OAAO,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;AACjE,CAAC,CAAC;AAOF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAiB,EAAE;IACzD,KAAK,MAAM,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;QACrF,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACtE,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC1C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAEnD,CAAC;YACF,IAAI,GAAG,CAAC,YAAY,EAAE,KAAK;gBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;QACnE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,SAAiB,EAAE,MAAc,EAAU,EAAE,CAC9E;;;eAGa,UAAU;mBACN,SAAS;eACb,MAAM;;;;;;;;;;;;;;;;;CAiBpB,CAAC"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.4.9";
1
+ export declare const VERSION = "0.4.10";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,OAAO,UAAU,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,OAAO,WAAW,CAAC"}
package/dist/version.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // AUTO-GENERATED FILE — DO NOT EDIT BY HAND.
2
2
  //
3
- // The literal "0.4.9" below is a placeholder. In CI release
3
+ // The literal "0.4.10" below is a placeholder. In CI release
4
4
  // builds (scripts/build-binaries.sh), `sed` replaces it with the real version
5
5
  // string before each `bun build --compile` invocation, and the build asserts
6
6
  // the version was actually embedded by greping the binary. This is the
@@ -10,7 +10,7 @@
10
10
  // silent).
11
11
  //
12
12
  // In local dev (`tsx src/index.ts`) the placeholder stays put and `pushto
13
- // --version` reports the literal "0.4.9" — a giveaway
13
+ // --version` reports the literal "0.4.10" — a giveaway
14
14
  // that you're on the source tree, not a release build.
15
- export const VERSION = "0.4.9";
15
+ export const VERSION = "0.4.10";
16
16
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,4DAA4D;AAC5D,8EAA8E;AAC9E,6EAA6E;AAC7E,uEAAuE;AACvE,wEAAwE;AACxE,6EAA6E;AAC7E,wEAAwE;AACxE,WAAW;AACX,EAAE;AACF,0EAA0E;AAC1E,sDAAsD;AACtD,uDAAuD;AACvD,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,6DAA6D;AAC7D,8EAA8E;AAC9E,6EAA6E;AAC7E,uEAAuE;AACvE,wEAAwE;AACxE,6EAA6E;AAC7E,wEAAwE;AACxE,WAAW;AACX,EAAE;AACF,0EAA0E;AAC1E,uDAAuD;AACvD,uDAAuD;AACvD,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushto/cli",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
4
4
  "description": "Deploy to pushto.host from your terminal",
5
5
  "type": "module",
6
6
  "bin": {