mapples 0.2.0-beta.0 → 0.2.0-beta.3

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 (96) hide show
  1. package/README.md +70 -22
  2. package/dist/adopt/scan.d.ts +8 -2
  3. package/dist/adopt/scan.js +31 -13
  4. package/dist/adopt/scan.js.map +1 -1
  5. package/dist/api/auth.d.ts +2 -0
  6. package/dist/api/auth.js +28 -6
  7. package/dist/api/auth.js.map +1 -1
  8. package/dist/api/client.d.ts +10 -1
  9. package/dist/api/client.js +24 -4
  10. package/dist/api/client.js.map +1 -1
  11. package/dist/api/commit.d.ts +9 -0
  12. package/dist/api/commit.js +35 -0
  13. package/dist/api/commit.js.map +1 -1
  14. package/dist/api/errors.js +8 -0
  15. package/dist/api/errors.js.map +1 -1
  16. package/dist/api/objects.d.ts +22 -5
  17. package/dist/api/objects.js +151 -10
  18. package/dist/api/objects.js.map +1 -1
  19. package/dist/api/poll.d.ts +5 -3
  20. package/dist/api/poll.js +17 -6
  21. package/dist/api/poll.js.map +1 -1
  22. package/dist/assets/assets.d.ts +9 -0
  23. package/dist/assets/assets.js +33 -4
  24. package/dist/assets/assets.js.map +1 -1
  25. package/dist/codegen/emit.d.ts +27 -1
  26. package/dist/codegen/emit.js +130 -9
  27. package/dist/codegen/emit.js.map +1 -1
  28. package/dist/codegen/imports.d.ts +2 -0
  29. package/dist/codegen/imports.js +38 -0
  30. package/dist/codegen/imports.js.map +1 -1
  31. package/dist/codegen/instances.d.ts +16 -0
  32. package/dist/codegen/instances.js +141 -0
  33. package/dist/codegen/instances.js.map +1 -0
  34. package/dist/codegen/styles.d.ts +11 -0
  35. package/dist/codegen/styles.js +131 -0
  36. package/dist/codegen/styles.js.map +1 -0
  37. package/dist/commands/impl/createImpl.js +8 -4
  38. package/dist/commands/impl/createImpl.js.map +1 -1
  39. package/dist/commands/impl/initImpl.js +5 -4
  40. package/dist/commands/impl/initImpl.js.map +1 -1
  41. package/dist/commands/impl/syncImpl.js +20 -2
  42. package/dist/commands/impl/syncImpl.js.map +1 -1
  43. package/dist/merge/applyOps.d.ts +1 -1
  44. package/dist/merge/applyOps.js +33 -2
  45. package/dist/merge/applyOps.js.map +1 -1
  46. package/dist/merge/diff.d.ts +1 -1
  47. package/dist/merge/diff.js +30 -17
  48. package/dist/merge/diff.js.map +1 -1
  49. package/dist/merge/threeWay.d.ts +1 -1
  50. package/dist/merge/threeWay.js +38 -6
  51. package/dist/merge/threeWay.js.map +1 -1
  52. package/dist/merge/toEdits.d.ts +1 -1
  53. package/dist/merge/toEdits.js +4 -1
  54. package/dist/merge/toEdits.js.map +1 -1
  55. package/dist/nav/navigatorTree.d.ts +78 -0
  56. package/dist/nav/navigatorTree.js +410 -0
  57. package/dist/nav/navigatorTree.js.map +1 -0
  58. package/dist/nav/placement.d.ts +53 -0
  59. package/dist/nav/placement.js +260 -0
  60. package/dist/nav/placement.js.map +1 -0
  61. package/dist/nav/routeTree.d.ts +8 -2
  62. package/dist/nav/routeTree.js +79 -151
  63. package/dist/nav/routeTree.js.map +1 -1
  64. package/dist/nav/screenOptions.d.ts +15 -0
  65. package/dist/nav/screenOptions.js +213 -0
  66. package/dist/nav/screenOptions.js.map +1 -0
  67. package/dist/project/baseStore.d.ts +8 -0
  68. package/dist/project/baseStore.js +15 -0
  69. package/dist/project/baseStore.js.map +1 -1
  70. package/dist/project/componentsMap.d.ts +7 -0
  71. package/dist/project/componentsMap.js +21 -0
  72. package/dist/project/componentsMap.js.map +1 -0
  73. package/dist/project/config.d.ts +12 -3
  74. package/dist/project/config.js +11 -2
  75. package/dist/project/config.js.map +1 -1
  76. package/dist/project/env.d.ts +10 -3
  77. package/dist/project/env.js +23 -5
  78. package/dist/project/env.js.map +1 -1
  79. package/dist/project/pagesMap.d.ts +2 -0
  80. package/dist/project/pagesMap.js.map +1 -1
  81. package/dist/services/adoptService.d.ts +3 -0
  82. package/dist/services/adoptService.js +346 -38
  83. package/dist/services/adoptService.js.map +1 -1
  84. package/dist/services/clientFactory.js +4 -2
  85. package/dist/services/clientFactory.js.map +1 -1
  86. package/dist/services/doctorService.js +77 -66
  87. package/dist/services/doctorService.js.map +1 -1
  88. package/dist/services/syncEngine.d.ts +7 -0
  89. package/dist/services/syncEngine.js +428 -292
  90. package/dist/services/syncEngine.js.map +1 -1
  91. package/dist/types.d.ts +21 -1
  92. package/dist/types.js +22 -0
  93. package/dist/types.js.map +1 -1
  94. package/package.json +2 -2
  95. package/templates/app/_layout.tsx +3 -0
  96. package/templates/mapples/sid.d.ts +6 -0
package/README.md CHANGED
@@ -1,42 +1,90 @@
1
1
  # mapples
2
2
 
3
3
  Two-way code sync between **Mapples Creator** and your Expo project (RFC-0002, over the JPATCH/1
4
- protocol from RFC-0001). Screens live as generated, editable TSX in your repo — `$sid`-tagged JSX
5
- is the code-side truth, extracted back into RenderDom and merged 3-way against the canvas.
4
+ protocol from RFC-0001). Screens and components live as generated, editable TSX in your repo —
5
+ `$sid`-tagged JSX is the code-side truth, extracted back into RenderDom and merged 3-way against
6
+ the canvas.
6
7
 
7
8
  ```bash
8
- npx mapples create my-app --project <projectId> # scaffold a connected Expo app
9
- npx mapples init --project <projectId> # link an existing Expo app
10
- npx mapples sync # pull + push in one run
11
- npx mapples adopt app/settings.tsx # force-adopt a plain RN screen
12
- npx mapples doctor # $sid lint + drift check
9
+ npx mapples create my-app --secret <project API secret> # scaffold a connected Expo app
10
+ npx mapples init --secret <project API secret> # link an existing Expo app
11
+ npx mapples sync # pull + push in one run
12
+ npx mapples sync --yes # …accepting every adoption proposal
13
+ npx mapples adopt app/settings.tsx # adopt a plain RN screen, no prompt
14
+ npx mapples doctor # $sid lint + drift check
15
+ ```
16
+
17
+ The project API secret comes from Creator (Project → Settings). It identifies the project and
18
+ authenticates the CLI; it is stored in `.mapples/secret` (git-ignored) or read from
19
+ `MAPPLES_SECRET`. A read-scoped secret pulls only; pushes need a write-scoped one.
20
+
21
+ ## Where code lives
22
+
23
+ | In Creator | In your repo |
24
+ | ------------------------------ | ------------------------------------------------------------------- |
25
+ | A screen inside a navigator | Its expo-router route file: `app/<segment>.tsx` |
26
+ | A screen outside any section | `mapples/pages/<Name>.tsx` — moves into `app/` once it is placed |
27
+ | Navigators (stack/tabs/drawer) | CLI-owned `app/**/_layout.tsx`, regenerated every sync |
28
+ | A saved component | `mapples/components/<Name>.tsx` |
29
+ | A component placed on a screen | `import Card from '../mapples/components/Card'` + `<Card $sid … />` |
30
+ | Theme | `mapples/theme.ts` |
31
+ | Assets | `mapples/assets/` + generated `assetMap.ts` |
32
+
33
+ A routed file opens with a `// mapples-route: <id>` marker: renaming the file renames the route
34
+ in Creator, and a Creator rename moves the file. Apps born from `mapples create` own `app/`
35
+ from the root `_layout.tsx`; apps linked with `mapples init` keep the `app/(mapples)` group.
36
+
37
+ Generated files keep their styles in a dictionary below the component, the way hand-written
38
+ Mapples code does — never inline:
39
+
40
+ ```tsx
41
+ export default function Login() {
42
+ return <Text $sid="nd_…" text="Sign In" styled={{ style: styles.signInText }} />;
43
+ }
44
+
45
+ const styles = Styler.create({
46
+ signInText: { fontSize: 24, fontWeight: 'bold' },
47
+ });
13
48
  ```
14
49
 
15
50
  ## What sync does
16
51
 
17
- 1. Extracts every `*Mapplet.tsx` (`$sid` JSX → RenderDom; hooks/handlers/wrappers are invisible).
18
- 2. Pulls the delta since the last synced HEAD (`GET ?since`, cold bootstrap when too far behind).
19
- 3. 3-way merges per `$sid` node, per prop key: disjoint edits auto-merge; same-prop or
52
+ 1. Adopts new files you wrote (`app/*.tsx`, `mapples/pages/*.tsx`, `mapples/components/*.tsx`)
53
+ after a prompt (`--yes` to accept, `--no-adopt` to skip): react-native primitives become the
54
+ matching `@mapples/ui` components with `styled` props, anything else is wrapped as an opaque
55
+ `Custom` node; a component file becomes a Creator component, and a page that uses it links
56
+ to it in the same run.
57
+ 2. Extracts every managed file (`$sid` JSX → RenderDom; hooks, handlers and wrappers are
58
+ invisible). An element you added without a `$sid` is tagged the same way adoption would tag
59
+ it — it never stays invisible. A `styled={{ style: styles.card }}` reference is read through
60
+ your `StyleSheet.create` / `Styler.create` / plain-object dictionary.
61
+ 3. Pulls the delta since the last synced HEAD (cold bootstrap when too far behind).
62
+ 4. 3-way merges per `$sid` node, per prop key: disjoint edits auto-merge; same-prop or
20
63
  delete-vs-edit conflicts **deprecate** the file (`_depr_<ts>_<name>.tsx.old` — your version is
21
64
  never overwritten or deleted) and regenerate it from Creator.
22
- 4. Writes remote changes into your files **surgically** — user code is preserved byte-for-byte.
23
- 5. Pushes your edits as one JPATCH transaction; 409s rebase and retry with the same txId; going
65
+ 5. Writes remote changes into your files **surgically** — user code is preserved byte-for-byte.
66
+ A Creator style edit lands in the dictionary entry the tag references when that element is
67
+ its only reader, and inline (with a warning) when the entry is shared.
68
+ 6. Pushes your edits as JPATCH transactions of at most 200 ops; 409s rebase and retry; going
24
69
  offline parks ops in `.mapples/outbox/` and drains them next run.
25
- 6. Rewrites client-minted `c_` ids to server ids from the response `idMap`.
70
+ 7. Rewrites client-minted `c_` ids to server ids from the response `idMap`.
26
71
 
27
- Also synced: navigation ↔ `app/(mapples)/` route tree (layouts CLI-owned, wrappers create-once —
28
- rename a wrapper file to rename the route), style ↔ `mapples/theme.ts`, and assets ↔
29
- `mapples/assets/` + generated `assetMap.ts`.
72
+ Every lossy step is reported: expression props keep their last-known canvas value
73
+ (`NON_LITERAL_PROP`), props a component instance cannot carry stay in code only, and so on.
74
+ Nothing is dropped silently.
30
75
 
31
76
  ## Project state
32
77
 
33
78
  ```
34
79
  .mapples/
35
- config.json # projectId, apiUrl, appDir, routesDir
36
- head # last synced HEAD + seq
37
- pages.json # pageId <-> file mapping
38
- base/ # canonical JSON per entity at the last synced HEAD
39
- outbox/ # parked transactions (offline)
80
+ config.json # projectId, apiUrl, pagesDir, routesDir, componentsDir, schema — committable
81
+ secret # project API secret — git-ignored (or MAPPLES_SECRET)
82
+ head # last synced HEAD + seq
83
+ pages.json # pageId <-> file mapping (+ route)
84
+ components.json # componentId <-> file mapping
85
+ base/ # canonical JSON per entity at the last synced HEAD
86
+ outbox/ # parked transactions (offline)
40
87
  ```
41
88
 
42
- Auth: set `MAPPLES_TOKEN` in the environment.
89
+ `mapples/sid.d.ts` declares the transient JSX attributes (`$sid`, `$refs`, `$data`, `$actions`,
90
+ `$fallback`); `babel-plugin-mapples-sid` strips them from production bundles.
@@ -1,4 +1,10 @@
1
- import type { PagesMap } from '../project/pagesMap.js';
2
1
  import type { AdoptCandidate } from '../types.js';
3
- export declare function scanForCandidates(root: string, pagesMap: PagesMap): AdoptCandidate[];
2
+ export interface ScanDirs {
3
+ routesDir: string;
4
+ pagesDir: string;
5
+ }
6
+ export declare function isUnder(file: string, dir: string): boolean;
7
+ /** Files pages.json and components.json already own. */
8
+ export declare function managedFiles(root: string): Set<string>;
9
+ export declare function scanForCandidates(root: string, managed: Set<string>, dirs: ScanDirs): AdoptCandidate[];
4
10
  export declare function toRelative(root: string, file: string): string;
@@ -1,12 +1,32 @@
1
- // Adoption scan: exported React components under app/ + mapples/ with no $sid
2
- // and absent from the pages manifest. Unadopted files are never touched.
1
+ // Adoption scan: exported React components under the route tree, the pages
2
+ // directory and app/ + mapples/ with no $sid and absent from the pages and
3
+ // components manifests. Unadopted files are never touched.
4
+ //
5
+ // Classification follows the file layout (RFC-0002 §5): a file under
6
+ // routesDir is a ROUTED page (it joins the navigation at its position), one
7
+ // under pagesDir — or elsewhere in app/ outside the managed tree — is a page
8
+ // outside the navigation, anything else is a component.
3
9
  import { existsSync, readFileSync, readdirSync } from 'node:fs';
4
- import { join, relative, sep } from 'node:path';
10
+ import { isAbsolute, join, relative, sep } from 'node:path';
5
11
  import { scanComponents } from '@mapples/sid-ast';
6
- const SCAN_DIRS = ['app', 'mapples'];
7
- export function scanForCandidates(root, pagesMap) {
8
- const managed = new Set(Object.values(pagesMap).map((m) => m.file));
12
+ import { readComponentsMap } from '../project/componentsMap.js';
13
+ import { readPagesMap } from '../project/pagesMap.js';
14
+ export function isUnder(file, dir) {
15
+ const rel = relative(dir, file);
16
+ return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel);
17
+ }
18
+ /** Files pages.json and components.json already own. */
19
+ export function managedFiles(root) {
20
+ return new Set([
21
+ ...Object.values(readPagesMap(root)).map((m) => m.file),
22
+ ...Object.values(readComponentsMap(root)).map((m) => m.file),
23
+ ]);
24
+ }
25
+ export function scanForCandidates(root, managed, dirs) {
9
26
  const candidates = [];
27
+ const scanRoots = [
28
+ ...new Set(['app', 'mapples', dirs.routesDir.split(sep)[0], dirs.pagesDir.split(sep)[0]]),
29
+ ];
10
30
  const walk = (dir) => {
11
31
  const abs = join(root, dir);
12
32
  if (!existsSync(abs))
@@ -30,18 +50,16 @@ export function scanForCandidates(root, pagesMap) {
30
50
  if (info.hasSid || !info.hasJsx)
31
51
  continue;
32
52
  if (info.markers.length > 0)
33
- continue; // route wrappers / generated files
53
+ continue; // generated files / files already carrying a route
34
54
  const componentName = info.exportedComponents[0];
35
55
  if (!componentName)
36
56
  continue;
37
- candidates.push({
38
- file: rel,
39
- componentName,
40
- kind: rel.split(sep)[0] === 'app' ? 'page' : 'component',
41
- });
57
+ const routed = isUnder(rel, dirs.routesDir);
58
+ const page = routed || isUnder(rel, dirs.pagesDir) || rel.split(sep)[0] === 'app';
59
+ candidates.push({ file: rel, componentName, kind: page ? 'page' : 'component', routed });
42
60
  }
43
61
  };
44
- for (const dir of SCAN_DIRS)
62
+ for (const dir of scanRoots)
45
63
  walk(dir);
46
64
  return candidates.sort((a, b) => (a.file < b.file ? -1 : 1));
47
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/adopt/scan.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/adopt/scan.ts"],"names":[],"mappings":"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"}
@@ -2,4 +2,6 @@ export interface ResolvedProject {
2
2
  projectId: string;
3
3
  name?: string;
4
4
  }
5
+ /** Decode the `project_uuid` claim from an API-key JWT. Null when the secret is not a JWT. */
6
+ export declare function decodeKeyProject(secret: string): string | null;
5
7
  export declare function resolveProject(apiUrl: string, secret: string): Promise<ResolvedProject>;
package/dist/api/auth.js CHANGED
@@ -1,18 +1,40 @@
1
- // Secret -> project resolution. The API secret (Creator: Project -> Settings)
2
- // both authenticates the CLI and identifies the project; the JPATCH paths
3
- // still need the pid, so we resolve it once and cache it in config.json.
1
+ // Secret -> project resolution (RFC-0003). A Mapples API key is an HS256 JWT
2
+ // whose payload carries `project_uuid` — the key both authenticates and
3
+ // identifies the project, so resolution is a LOCAL decode of the payload (no
4
+ // signature check client-side; the server verifies on every request). The
5
+ // HTTP fallback exists only for opaque dev secrets (the mock server's sk_…).
4
6
  import axios from 'axios';
7
+ /** Decode the `project_uuid` claim from an API-key JWT. Null when the secret is not a JWT. */
8
+ export function decodeKeyProject(secret) {
9
+ const parts = secret.split('.');
10
+ if (parts.length !== 3)
11
+ return null;
12
+ try {
13
+ const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8'));
14
+ return typeof payload.project_uuid === 'string' && payload.project_uuid.length > 0
15
+ ? payload.project_uuid
16
+ : null;
17
+ }
18
+ catch {
19
+ // Not a JWT payload we can read — fall through to the HTTP fallback.
20
+ return null;
21
+ }
22
+ }
5
23
  export async function resolveProject(apiUrl, secret) {
24
+ const local = decodeKeyProject(secret);
25
+ if (local)
26
+ return { projectId: local };
27
+ // Opaque secret (mock server): resolve over HTTP with the real auth header.
6
28
  const res = await axios.get(`${apiUrl.replace(/\/+$/, '')}/auth/project`, {
7
- headers: { Authorization: `Bearer ${secret}` },
29
+ headers: { 'X-API-Key': secret },
8
30
  validateStatus: () => true,
9
31
  timeout: 30_000,
10
32
  });
11
33
  if (res.status === 200 && typeof res.data.projectId === 'string') {
12
34
  return res.data;
13
35
  }
14
- if (res.status === 401 || res.status === 403) {
15
- throw new Error('the API secret was rejected — generate a fresh one in Creator (Project → Settings) and re-run with --secret');
36
+ if (res.status === 401 || res.status === 403 || res.status === 404) {
37
+ throw new Error('this does not look like a Mapples API key — generate one in Creator (Project → Settings) and re-run with --secret');
16
38
  }
17
39
  throw new Error(`could not resolve the project from the API secret (HTTP ${res.status})`);
18
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,yEAAyE;AAEzE,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc,EAAE,MAAc;IACjE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,eAAe,EAAE;QACxE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE;QAC9C,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;QAC1B,OAAO,EAAE,MAAM;KAChB,CAAC,CAAC;IACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,OAAQ,GAAG,CAAC,IAAgC,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC9F,OAAO,GAAG,CAAC,IAAuB,CAAC;IACrC,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CACb,6GAA6G,CAC9G,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,2DAA2D,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5F,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wEAAwE;AACxE,6EAA6E;AAC7E,0EAA0E;AAC1E,6EAA6E;AAE7E,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAE9E,CAAC;QACF,OAAO,OAAO,OAAO,CAAC,YAAY,KAAK,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAChF,CAAC,CAAC,OAAO,CAAC,YAAY;YACtB,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;QACrE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc,EAAE,MAAc;IACjE,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,KAAK;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAEvC,4EAA4E;IAC5E,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,eAAe,EAAE;QACxE,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE;QAChC,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;QAC1B,OAAO,EAAE,MAAM;KAChB,CAAC,CAAC;IACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,OAAQ,GAAG,CAAC,IAAgC,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC9F,OAAO,GAAG,CAAC,IAAuB,CAAC;IACrC,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CACb,mHAAmH,CACpH,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,2DAA2D,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5F,CAAC"}
@@ -3,9 +3,12 @@ import type { Bootstrap, CommitOk, Delta, Envelope } from '../types.js';
3
3
  export interface JpatchClientOptions {
4
4
  baseUrl: string;
5
5
  projectId: string;
6
+ /** Project API key (Creator → Project → Settings); sent as X-API-Key (RFC-0003). */
6
7
  token?: string;
7
8
  actor?: string;
8
9
  origin?: string;
10
+ /** Host serving asset bodies (per-stage assets host); defaults to baseUrl. */
11
+ assetsBaseUrl?: string;
9
12
  }
10
13
  /**
11
14
  * Thin, faithful JPATCH/1 transport (RFC-0001 §5–§8). No retry logic here —
@@ -16,14 +19,20 @@ export declare class JpatchClient {
16
19
  readonly projectId: string;
17
20
  readonly actor: string | undefined;
18
21
  readonly origin: string | undefined;
22
+ readonly assetsBaseUrl: string;
19
23
  constructor(opts: JpatchClientOptions);
20
24
  private path;
21
25
  commitRaw(envelope: Envelope): Promise<CommitOk>;
22
- pullOnce(since: string): Promise<Delta>;
26
+ /** One delta page. The cursor is a SEQUENCE number (`since_seq`), not a head. */
27
+ pullOnce(sinceSeq: number): Promise<Delta>;
23
28
  bootstrap(): Promise<Bootstrap>;
24
29
  getObject(hash: string): Promise<unknown>;
25
30
  /** Binary blob fetch (asset bodies, addressed as `sha256:<hex>`). */
26
31
  getObjectBytes(hash: string): Promise<Uint8Array>;
32
+ /** Batched blob fetch: POST objects/get {hashes} -> {objects} (RFC-0001 §6, key-readable). */
33
+ objectsGet(hashes: string[]): Promise<Record<string, unknown>>;
34
+ /** Fetch raw bytes for an asset `link` (served from the assets host). */
35
+ getBytesAtPath(path: string): Promise<Uint8Array>;
27
36
  /** Which of these content hashes is the store missing? Returns hash -> signed PUT URL. */
28
37
  have(hashes: string[]): Promise<Record<string, string>>;
29
38
  history(limit?: number): Promise<{
@@ -9,20 +9,23 @@ export class JpatchClient {
9
9
  projectId;
10
10
  actor;
11
11
  origin;
12
+ assetsBaseUrl;
12
13
  constructor(opts) {
13
14
  this.projectId = opts.projectId;
14
15
  this.actor = opts.actor;
15
16
  this.origin = opts.origin;
17
+ this.assetsBaseUrl = (opts.assetsBaseUrl ?? opts.baseUrl).replace(/\/+$/, '');
16
18
  this.http = axios.create({
17
19
  baseURL: opts.baseUrl.replace(/\/+$/, ''),
18
- headers: opts.token ? { Authorization: `Bearer ${opts.token}` } : {},
20
+ headers: opts.token ? { 'X-API-Key': opts.token } : {},
19
21
  // We map error bodies ourselves; axios must hand them to us.
20
22
  validateStatus: () => true,
21
23
  timeout: 30_000,
22
24
  });
23
25
  }
24
26
  path(suffix = '') {
25
- return `/${this.projectId}/canvas${suffix}`;
27
+ // Real backend shape (service--mapplesorg): plural `projects` prefix.
28
+ return `/projects/${this.projectId}/canvas${suffix}`;
26
29
  }
27
30
  async commitRaw(envelope) {
28
31
  const res = await this.http.post(this.path(), envelope);
@@ -30,8 +33,9 @@ export class JpatchClient {
30
33
  return res.data;
31
34
  throw errorFromBody(res.status, res.data);
32
35
  }
33
- async pullOnce(since) {
34
- const res = await this.http.get(this.path(), { params: { since } });
36
+ /** One delta page. The cursor is a SEQUENCE number (`since_seq`), not a head. */
37
+ async pullOnce(sinceSeq) {
38
+ const res = await this.http.get(this.path(), { params: { since_seq: sinceSeq } });
35
39
  if (res.status === 200)
36
40
  return res.data;
37
41
  throw errorFromBody(res.status, res.data);
@@ -57,6 +61,22 @@ export class JpatchClient {
57
61
  return new Uint8Array(res.data);
58
62
  throw errorFromBody(res.status, JSON.parse(Buffer.from(res.data).toString('utf8')));
59
63
  }
64
+ /** Batched blob fetch: POST objects/get {hashes} -> {objects} (RFC-0001 §6, key-readable). */
65
+ async objectsGet(hashes) {
66
+ const res = await this.http.post(this.path('/objects/get'), { hashes });
67
+ if (res.status === 200) {
68
+ return (res.data.objects ?? {});
69
+ }
70
+ throw errorFromBody(res.status, res.data);
71
+ }
72
+ /** Fetch raw bytes for an asset `link` (served from the assets host). */
73
+ async getBytesAtPath(path) {
74
+ const url = path.startsWith('http') ? path : `${this.assetsBaseUrl}${path}`;
75
+ const res = await this.http.get(url, { responseType: 'arraybuffer' });
76
+ if (res.status === 200)
77
+ return new Uint8Array(res.data);
78
+ throw errorFromBody(res.status, JSON.parse(Buffer.from(res.data).toString('utf8')));
79
+ }
60
80
  /** Which of these content hashes is the store missing? Returns hash -> signed PUT URL. */
61
81
  async have(hashes) {
62
82
  if (hashes.length > 500)
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,15 @@ import type { CommitOk, Envelope, JpatchOp } from '../types.js';
2
2
  import type { JpatchClient } from './client.js';
3
3
  export declare function mintTxId(): string;
4
4
  export declare function mintCid(): string;
5
+ /**
6
+ * Rewrite every cid that an earlier transaction already resolved (its `idMap`)
7
+ * to the server id, wherever it appears in `ops` — `id`, `data.parent`,
8
+ * children refs, props that point at sibling nodes. cids are transaction-scoped
9
+ * (RFC-0001 §5.2, invariant 5): once the create that minted one has committed,
10
+ * a later transaction must reference the DB id or the server answers
11
+ * CID_UNRESOLVED. Returns new objects; `ops` is left untouched.
12
+ */
13
+ export declare function resolveCids(ops: JpatchOp[], idMap: Record<string, string>): JpatchOp[];
5
14
  export interface CommitParams {
6
15
  base: string;
7
16
  ops: JpatchOp[];
@@ -1,11 +1,39 @@
1
1
  import { ulid } from 'ulid';
2
2
  import { isNetworkError } from './client.js';
3
+ import { JpatchError } from './errors.js';
3
4
  export function mintTxId() {
4
5
  return `tx_${ulid()}`;
5
6
  }
6
7
  export function mintCid() {
7
8
  return `c_${ulid()}`;
8
9
  }
10
+ /**
11
+ * Rewrite every cid that an earlier transaction already resolved (its `idMap`)
12
+ * to the server id, wherever it appears in `ops` — `id`, `data.parent`,
13
+ * children refs, props that point at sibling nodes. cids are transaction-scoped
14
+ * (RFC-0001 §5.2, invariant 5): once the create that minted one has committed,
15
+ * a later transaction must reference the DB id or the server answers
16
+ * CID_UNRESOLVED. Returns new objects; `ops` is left untouched.
17
+ */
18
+ export function resolveCids(ops, idMap) {
19
+ if (!Object.keys(idMap).some((k) => k.startsWith('c_')))
20
+ return ops;
21
+ const walk = (value) => {
22
+ if (typeof value === 'string') {
23
+ return value.startsWith('c_') && idMap[value] !== undefined ? idMap[value] : value;
24
+ }
25
+ if (Array.isArray(value))
26
+ return value.map(walk);
27
+ if (value !== null && typeof value === 'object') {
28
+ const out = {};
29
+ for (const [k, v] of Object.entries(value))
30
+ out[k] = walk(v);
31
+ return out;
32
+ }
33
+ return value;
34
+ };
35
+ return ops.map((op) => walk(op));
36
+ }
9
37
  export function buildEnvelope(client, params) {
10
38
  const envelope = {
11
39
  protocol: 'jpatch/1',
@@ -36,6 +64,13 @@ export async function commitWithTransportRetry(client, envelope, maxAttempts = 5
36
64
  return await client.commitRaw(envelope);
37
65
  }
38
66
  catch (err) {
67
+ if (err instanceof JpatchError && err.code === 'FORBIDDEN') {
68
+ // RFC-0003: read-scoped keys can pull but not push. Prefer the
69
+ // server's own guidance when it sends one.
70
+ const detail = err.message.replace(/^FORBIDDEN:\s*/, '');
71
+ throw new Error(`push rejected: ${detail ||
72
+ 'this API key is read-scoped — generate a read & write key in Creator (Project → Settings)'} (then re-run \`mapples init --secret <key>\`)`);
73
+ }
39
74
  if (!isNetworkError(err))
40
75
  throw err;
41
76
  lastErr = err;
@@ -1 +1 @@
1
- {"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/api/commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,UAAU,QAAQ;IACtB,OAAO,MAAM,IAAI,EAAE,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,OAAO,KAAK,IAAI,EAAE,EAAE,CAAC;AACvB,CAAC;AASD,MAAM,UAAU,aAAa,CAAC,MAAoB,EAAE,MAAoB;IACtE,MAAM,QAAQ,GAAa;QACzB,QAAQ,EAAE,UAAU;QACpB,MAAM,EAAE,CAAC;QACT,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,QAAQ,EAAE;QAC/B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,IAAI,EAAE;YACJ,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChD,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnD,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAC7B;KACF,CAAC;IACF,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS;QAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACvE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,MAAoB,EACpB,QAAkB,EAClB,WAAW,GAAG,CAAC;IAEf,IAAI,OAAgB,CAAC;IACrB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,OAAO,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;gBAAE,MAAM,GAAG,CAAC;YACpC,OAAO,GAAG,GAAG,CAAC;YACd,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IACD,MAAM,OAAO,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/api/commit.ts"],"names":[],"mappings":"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"}
@@ -60,6 +60,14 @@ export class UnexpectedResponseError extends Error {
60
60
  }
61
61
  }
62
62
  export function errorFromBody(status, body) {
63
+ // The real backend's auth denials carry {detail} without a code field.
64
+ if (status === 403 &&
65
+ typeof body === 'object' &&
66
+ body !== null &&
67
+ !('code' in body) &&
68
+ typeof body.detail === 'string') {
69
+ return new JpatchError('FORBIDDEN', body.detail);
70
+ }
63
71
  if (isJpatchErrorBody(body)) {
64
72
  const { code, message, ...rest } = body;
65
73
  if (code === 'HEAD_MISMATCH') {
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/api/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/api/errors.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,27 @@
1
- import type { Bootstrap, RenderDomNode } from '../types.js';
1
+ import { type Bootstrap, type RenderDomNode } from '../types.js';
2
2
  import type { JpatchClient } from './client.js';
3
3
  export interface PageEntity {
4
4
  id: string;
5
5
  name: string;
6
6
  route: string;
7
7
  root: RenderDomNode;
8
+ /** Creator page uuid — navigator route targets reference pages by this. */
9
+ uuid?: string;
8
10
  }
9
11
  export interface ComponentEntity {
10
12
  id: string;
11
13
  name: string;
12
14
  root: RenderDomNode;
15
+ /** Creator component uuid — a page's `ComponentInstance` nodes link to it. */
16
+ uuid?: string;
13
17
  }
14
18
  export interface NavigationDocument {
15
- routes: NavigationRoute[];
16
- layouts: Record<string, unknown>;
19
+ /** Legacy/CLI route list. The real backend serves a navigator document
20
+ * (`data.navigators`) without this field — then route-tree codegen is
21
+ * skipped with a visible note; the raw doc is preserved in base. */
22
+ routes?: NavigationRoute[];
23
+ layouts?: Record<string, unknown>;
24
+ [k: string]: unknown;
17
25
  }
18
26
  export interface NavigationRoute {
19
27
  id: string;
@@ -28,11 +36,18 @@ export interface StyleConfig {
28
36
  sizing: Record<string, unknown>;
29
37
  }
30
38
  export type AssetIndex = Record<string, {
31
- sha256: string;
32
- mime: string;
39
+ sha256?: string;
40
+ mime?: string;
33
41
  w?: number;
34
42
  h?: number;
35
43
  name?: string;
44
+ /** Real backend fields (dev): server-relative body URL + file metadata. */
45
+ link?: string;
46
+ file_name?: string;
47
+ extension?: string;
48
+ type?: string;
49
+ uuid?: string;
50
+ [k: string]: unknown;
36
51
  }>;
37
52
  export interface ProjectState {
38
53
  head: string;
@@ -43,6 +58,8 @@ export interface ProjectState {
43
58
  style: StyleConfig;
44
59
  assets: AssetIndex;
45
60
  }
61
+ /** Pages on the real backend carry no route; derive a stable one from the name. */
62
+ export declare function deriveRoute(name: string): string;
46
63
  /** Cold bootstrap: walk the manifest and fetch every blob (RFC-0001 §6). */
47
64
  export declare function fetchProjectState(client: JpatchClient, boot: Bootstrap): Promise<ProjectState>;
48
65
  /**