@volter/twin-catalog 0.2.40 → 0.2.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/bin/twin-catalog.mjs +3 -1
- package/catalog.json +69 -3
- package/content/100cf4069352dee18bcb1f8ef9198c637ce1842d42f66477a6a62702c24f9f13.json +27 -0
- package/content/1f197a74b85508b9af3089c0a8807580b479c90f5ad38d1cb0413d7ef4b06861.json +27 -0
- package/content/1fa7500b80e0c420b91e602419e1185bb2b2871c338e74eb7d5d20845e167e3c.json +27 -0
- package/content/298a3364ab17a8b5c8b07b21d7ff83c9402108bccabc6287ced0431890c7eda9.json +27 -0
- package/content/2c123aa480c3d787e21218b005870509fe48379ba534df5a2eed8d2db5956596.json +27 -0
- package/content/2f905a18997aea40b709c4d4ea7adce45d4b080cf2216353d09b0cb6a910c3f7.json +27 -0
- package/content/32255ffe1d7c2e67218d1a05799128096033136f9d4963b0d55fcb8b71c09e89.json +27 -0
- package/content/4edaec8cd2e55c04f66245309742a63c36f102320ef221927ff93d97b3b268b9.json +27 -0
- package/content/5eeaa5e7c2a08c8c0818489c40e7b818c114bd74f5c1b8186e0de69f8792049c.json +27 -0
- package/content/66285aa1b8bccb8fe943294975108f303bc51ee310c33633d7454afa631e913b.json +27 -0
- package/content/6f9f4c4659dc8d86e42363050c0ee444e4f1e05409866bf4ee3b54d12a3c2cc2.json +27 -0
- package/content/871d902e2c0d3e14a5a9c90fca585f47f5e0989442abe099ec185b5541c54e14.json +27 -0
- package/content/8c35ee3b7e5272a335eccc4e2527b8135eebaeee75c1aab1f874f520fe97de71.json +28 -0
- package/content/a37094107a6552d8cb5b49011973a76330b48d392f66a21ec957923c3c0641fd.json +27 -0
- package/content/d66776b9b0d4c8b19b09a012f455f5b6697b39fc2205b2bb64e7a3855e734e84.json +27 -0
- package/content/fa756dfc21662a70679a660dd88fcb2b4f8bad30f408f1134cd87b0668289fc6.json +27 -0
- package/docs/operations.md +19 -0
- package/docs/process.md +13 -3
- package/lib/browse.d.mts +3 -1
- package/lib/browse.mjs +16 -5
- package/lib/content.mjs +87 -0
- package/lib/publication.mjs +9 -1
- package/package.json +5 -4
- package/runner/prepare.mjs +6 -2
package/README.md
CHANGED
|
@@ -63,6 +63,10 @@ node bin/twin-catalog.mjs build --out /tmp/new-catalog-output
|
|
|
63
63
|
The build requires committed admission records and a new output directory. It generates data without importing packs.
|
|
64
64
|
The website and hosted runtime consume this artifact independently; publishing it does not deploy either.
|
|
65
65
|
|
|
66
|
+
Maintainers use `node bin/twin-catalog.mjs capture-content` to retain the exact artifacts' manifests and READMEs
|
|
67
|
+
in a maintenance change. The distributed reader exposes them as release documentation, separate from assessment
|
|
68
|
+
measurements. See [release information](docs/process.md#release-information-for-users).
|
|
69
|
+
|
|
66
70
|
For discovery, use the JSON-only reader against an installed index:
|
|
67
71
|
|
|
68
72
|
```sh
|
package/bin/twin-catalog.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import { persistEvidence } from '../lib/evidence.mjs';
|
|
|
11
11
|
import { propose } from '../lib/propose.mjs';
|
|
12
12
|
import { browse } from '../lib/browse.mjs';
|
|
13
13
|
import { register } from '../lib/register.mjs';
|
|
14
|
+
import { captureContent } from '../lib/content.mjs';
|
|
14
15
|
|
|
15
16
|
const [command, ...args] = process.argv.slice(2);
|
|
16
17
|
const arg = (name, fallback) => { const at = args.indexOf(`--${name}`); if (at < 0) return fallback; requireThat(args[at + 1] && !args[at + 1].startsWith('--'), `--${name} needs a value`); return args[at + 1]; };
|
|
@@ -63,6 +64,7 @@ try {
|
|
|
63
64
|
break;
|
|
64
65
|
}
|
|
65
66
|
case 'build': result = build(root, resolve(arg('out', 'dist'))); break;
|
|
67
|
+
case 'capture-content': result = await captureContent(root, builtIndex(root), policy().registry); break;
|
|
66
68
|
case 'publish': {
|
|
67
69
|
const client = github();
|
|
68
70
|
const policyClient = process.env.CATALOG_READ_TOKEN ? new GitHub(client.repository, process.env.CATALOG_READ_TOKEN) : client;
|
|
@@ -73,7 +75,7 @@ try {
|
|
|
73
75
|
result = await publish(output, policy().registry);
|
|
74
76
|
break;
|
|
75
77
|
}
|
|
76
|
-
default: throw new Error('usage: twin-catalog register --source <id> --source-repository <owner/repo> --scope <@scope> [--out <sources.json>] | submit --source <id> --vendor <vendor> --package <@scope/name> --version <exact> | browse [--root <installed-index>] [--vendor <vendor>] [--package <@scope/name>] | assess-pr --pr <number> | check | defaults | build --out <new-directory> | publish | configure [--apply] | propose --from <submission-directory> --send');
|
|
78
|
+
default: throw new Error('usage: twin-catalog register --source <id> --source-repository <owner/repo> --scope <@scope> [--out <sources.json>] | submit --source <id> --vendor <vendor> --package <@scope/name> --version <exact> | browse [--root <installed-index>] [--vendor <vendor>] [--package <@scope/name>] | capture-content | assess-pr --pr <number> | check | defaults | build --out <new-directory> | publish | configure [--apply] | propose --from <submission-directory> --send');
|
|
77
79
|
}
|
|
78
80
|
console.log(JSON.stringify(result, null, 2));
|
|
79
81
|
} catch (error) { console.error(`twin-catalog: ${error.message ?? error}`); process.exitCode = 1; }
|
package/catalog.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"sourceCommit": "
|
|
4
|
-
"digest": "
|
|
3
|
+
"sourceCommit": "0bf8d1e4abbdf762531c875c432edf9516edf63b",
|
|
4
|
+
"digest": "5103e721dd9632a05ec4d5348d1b9e668ee092b3edf634c0e4b08f08efb76527",
|
|
5
5
|
"versions": [
|
|
6
6
|
{
|
|
7
7
|
"vendor": "tavily",
|
|
@@ -403,5 +403,71 @@
|
|
|
403
403
|
},
|
|
404
404
|
"assessed": true
|
|
405
405
|
}
|
|
406
|
-
]
|
|
406
|
+
],
|
|
407
|
+
"content": {
|
|
408
|
+
"100cf4069352dee18bcb1f8ef9198c637ce1842d42f66477a6a62702c24f9f13": {
|
|
409
|
+
"path": "content/100cf4069352dee18bcb1f8ef9198c637ce1842d42f66477a6a62702c24f9f13.json",
|
|
410
|
+
"sha256": "0a28646b4c4e9f7ce2d83cee9e1374954bf5407fc92f1fb6f7f50838ca331e5d"
|
|
411
|
+
},
|
|
412
|
+
"1f197a74b85508b9af3089c0a8807580b479c90f5ad38d1cb0413d7ef4b06861": {
|
|
413
|
+
"path": "content/1f197a74b85508b9af3089c0a8807580b479c90f5ad38d1cb0413d7ef4b06861.json",
|
|
414
|
+
"sha256": "d4580f49ef0fa050b3cb9b0f074e485ec35b53155ce932bd495916bb5196ec04"
|
|
415
|
+
},
|
|
416
|
+
"1fa7500b80e0c420b91e602419e1185bb2b2871c338e74eb7d5d20845e167e3c": {
|
|
417
|
+
"path": "content/1fa7500b80e0c420b91e602419e1185bb2b2871c338e74eb7d5d20845e167e3c.json",
|
|
418
|
+
"sha256": "36fe599b2d4ef0b664e5a17fe73dde972843c8f7cd64772c2fa23fb63bb5b885"
|
|
419
|
+
},
|
|
420
|
+
"298a3364ab17a8b5c8b07b21d7ff83c9402108bccabc6287ced0431890c7eda9": {
|
|
421
|
+
"path": "content/298a3364ab17a8b5c8b07b21d7ff83c9402108bccabc6287ced0431890c7eda9.json",
|
|
422
|
+
"sha256": "78e6efd8b0f164441f56367901ab4e371fe0dd830cc5725368f694d7965236a0"
|
|
423
|
+
},
|
|
424
|
+
"32255ffe1d7c2e67218d1a05799128096033136f9d4963b0d55fcb8b71c09e89": {
|
|
425
|
+
"path": "content/32255ffe1d7c2e67218d1a05799128096033136f9d4963b0d55fcb8b71c09e89.json",
|
|
426
|
+
"sha256": "fb0285fee0dbc55de661f355baf7b7bff9476ca78774e2d9b0c30a8fba8e0c86"
|
|
427
|
+
},
|
|
428
|
+
"2c123aa480c3d787e21218b005870509fe48379ba534df5a2eed8d2db5956596": {
|
|
429
|
+
"path": "content/2c123aa480c3d787e21218b005870509fe48379ba534df5a2eed8d2db5956596.json",
|
|
430
|
+
"sha256": "26748a27ddf964f25736515bb262a61eeaa78839ed9694a74fe687aa70b7555f"
|
|
431
|
+
},
|
|
432
|
+
"2f905a18997aea40b709c4d4ea7adce45d4b080cf2216353d09b0cb6a910c3f7": {
|
|
433
|
+
"path": "content/2f905a18997aea40b709c4d4ea7adce45d4b080cf2216353d09b0cb6a910c3f7.json",
|
|
434
|
+
"sha256": "77a9116b10b6e3c1581e04d790fa9a5fbc161870bef9ccea2eb87e772bf9f9a6"
|
|
435
|
+
},
|
|
436
|
+
"4edaec8cd2e55c04f66245309742a63c36f102320ef221927ff93d97b3b268b9": {
|
|
437
|
+
"path": "content/4edaec8cd2e55c04f66245309742a63c36f102320ef221927ff93d97b3b268b9.json",
|
|
438
|
+
"sha256": "e1fd483c0fd2ff0dda4a399adeaa5691d106e034d18544c0624ce094ac3cc4af"
|
|
439
|
+
},
|
|
440
|
+
"66285aa1b8bccb8fe943294975108f303bc51ee310c33633d7454afa631e913b": {
|
|
441
|
+
"path": "content/66285aa1b8bccb8fe943294975108f303bc51ee310c33633d7454afa631e913b.json",
|
|
442
|
+
"sha256": "bfb8d61110d948197d89218f38bb6a5f38f3a7c140ac61de77132016d16a9bf1"
|
|
443
|
+
},
|
|
444
|
+
"5eeaa5e7c2a08c8c0818489c40e7b818c114bd74f5c1b8186e0de69f8792049c": {
|
|
445
|
+
"path": "content/5eeaa5e7c2a08c8c0818489c40e7b818c114bd74f5c1b8186e0de69f8792049c.json",
|
|
446
|
+
"sha256": "08a5ac8f9d52cd2780b9833837cb87e63e3bdd394891196ad2a808011b2378be"
|
|
447
|
+
},
|
|
448
|
+
"d66776b9b0d4c8b19b09a012f455f5b6697b39fc2205b2bb64e7a3855e734e84": {
|
|
449
|
+
"path": "content/d66776b9b0d4c8b19b09a012f455f5b6697b39fc2205b2bb64e7a3855e734e84.json",
|
|
450
|
+
"sha256": "5f8815c56807a3e2965b499923b5fcec12fc697b074b4c96c3ba23f5c2886f72"
|
|
451
|
+
},
|
|
452
|
+
"6f9f4c4659dc8d86e42363050c0ee444e4f1e05409866bf4ee3b54d12a3c2cc2": {
|
|
453
|
+
"path": "content/6f9f4c4659dc8d86e42363050c0ee444e4f1e05409866bf4ee3b54d12a3c2cc2.json",
|
|
454
|
+
"sha256": "074d17670ee8aca87995d7f3b0be7f59889b9bd85a39cf12a2705df41c92ea9c"
|
|
455
|
+
},
|
|
456
|
+
"871d902e2c0d3e14a5a9c90fca585f47f5e0989442abe099ec185b5541c54e14": {
|
|
457
|
+
"path": "content/871d902e2c0d3e14a5a9c90fca585f47f5e0989442abe099ec185b5541c54e14.json",
|
|
458
|
+
"sha256": "992429eb3a85b381fa1b10691bcdc6f432e5d0dc4104dc01f3c39b27462af809"
|
|
459
|
+
},
|
|
460
|
+
"8c35ee3b7e5272a335eccc4e2527b8135eebaeee75c1aab1f874f520fe97de71": {
|
|
461
|
+
"path": "content/8c35ee3b7e5272a335eccc4e2527b8135eebaeee75c1aab1f874f520fe97de71.json",
|
|
462
|
+
"sha256": "73757b2d430bc03a0061b66c30a4c0aab004fe7b45b6b0fa7f0ba8f789cefc76"
|
|
463
|
+
},
|
|
464
|
+
"a37094107a6552d8cb5b49011973a76330b48d392f66a21ec957923c3c0641fd": {
|
|
465
|
+
"path": "content/a37094107a6552d8cb5b49011973a76330b48d392f66a21ec957923c3c0641fd.json",
|
|
466
|
+
"sha256": "d3b5649170d0209717e45b880dad7269b67351737ee3247bc0fd2a34dcf8aea5"
|
|
467
|
+
},
|
|
468
|
+
"fa756dfc21662a70679a660dd88fcb2b4f8bad30f408f1134cd87b0668289fc6": {
|
|
469
|
+
"path": "content/fa756dfc21662a70679a660dd88fcb2b4f8bad30f408f1134cd87b0668289fc6.json",
|
|
470
|
+
"sha256": "b62cbb2e36a4602b19a99fa6e03cb421850ed6b32012084da61b6b412880ad6e"
|
|
471
|
+
}
|
|
472
|
+
}
|
|
407
473
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "tavily",
|
|
7
|
+
"package": "@volter/twin-tavily",
|
|
8
|
+
"version": "1.0.1",
|
|
9
|
+
"integrity": "sha512-ABLgHRXQAk3LjrdP5bWBXhS4WW+w5/KyuL9UrPREgJc+nhE/Sd8bR+EZha0qaFFzaQIHqfuo9yPlxA/O3fMqlQ=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Tavily twin (Protocol 3): search over the World's web by lexical overlap, with a labeled stub answer (no web is searched, no model runs), and API keys. Built on @volter/world-core.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.59"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "tavily",
|
|
21
|
+
"bugs": null
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-tavily\n\nTavily Search (`POST /search`) and Extract (`POST /extract`) at `api.tavily.com`, for Postiz's shipped post-generator research and LibreChat's agent tools. Postiz's deployment key authorizes that feature; its caller is recorded in [demand.json](./journeys/demand.json). LibreChat users select and authenticate Tavily extraction in the in-app scraper key dialog; the exact caller commits are in [demand.json](./journeys/demand.json).\n\nThe World supplies a synthetic web corpus. Search ranks its pages by lexical overlap, with topic, domain restriction/preference, date, country, language, exact-phrase and safety options. It returns requested chunks, Markdown/text raw content, images/descriptions, favicon, publication date and usage. Answer and automatic-parameter judgment are scripted by the World or labeled deterministic stubs; no model or live web search runs. Advanced depth changes documented credit usage, and ultra-fast uses the corpus's supplied summary.\n\nExtract reads held corpus pages or a source the World routes through `ctx.vendorFetch`, including the application's own pages. An unregistered, failing or simulated slow source becomes a per-URL failure. Depth selects supplied advanced content; query/chunk limits, Markdown/text, images, favicon and timeout options apply to each URL. Credit accounting follows successful extractions, in groups of five per depth.\n\nAuthentication accepts the World-issued key in `Authorization: Bearer` or `api_key` in the body. The key is held by its hash and regenerated from the World's secret. No real credentials are needed.\n\nThe doors are:\n\n- `POST /_twin/app-credentials {}`: the dashboard's first key, returned identically on subsequent boots and wired to `TAVILY_API_KEY`.\n- `POST /_twin/pages {url, title, content, ...}`: a synthetic source page; the same URL replaces its record. Optional fields are `raw_content`, `text_content`, `advanced_content`, `summary`, `images` (URLs or `{url, description}` objects), `favicon`, `topic`, `published_date`, `country`, `language` (an ISO code), `unsafe` and `fetch_seconds`. These supply facts about a source that Tavily's API cannot create.\n\nThe World scenario supports `operationEquals` and `queryEquals`, status faults in Tavily's envelope, and search judgment `{parameters: {topic?, search_depth?}, answer?}`. Explicit input overrides automatic judgment; size options stay explicit. Source pages and their metadata are supplied through the door.\n\nCrawl, Map, Research, Feedback, Usage and Logs answer the gap: no measured caller, life act or refresh brings them into scope. This compute API has no vendor-backed deployment/refresh half; keys, corpus pages, request ids and extraction counts are private World bookkeeping. Real semantic ranking, crawling, model answers and billing are outside this deterministic corpus.\n\n[The life](./journeys/customer-life.json), [published examples](./journeys/vendor-examples.json), [coverage](./journeys/coverage.json) and [score](./journeys/score.json) retain their measured results. SDK cases are not owed by the measured clients: LibreChat uses raw fetch/axios for both operations, without the official `@tavily/core` SDK.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "stripe",
|
|
7
|
+
"package": "@volter/twin-stripe",
|
|
8
|
+
"version": "3.0.2",
|
|
9
|
+
"integrity": "sha512-5fkYOftyC6qC6kuO/q1VhXVjxHx0HIuiX0dtZj3BaE+L1UA1VeJvNzq5u/lT/rNSPQSYllfeKYZ4ZtM9GYGgzQ=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Stripe customer, checkout and billing workflows with synthetic state and the real Stripe SDK. Supported operations and hosted-page limits are documented in the README.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.68"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "stripe",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-stripe\n\nA local Stripe: the REST API the unmodified `stripe` SDK calls (`https://api.stripe.com/v1`), the hosted pages an\napplication sends a person through, and Stripe.js, over one state.\n\n## Use with an existing app\n\nIn an app that already uses this vendor, install this exact release and the product CLI:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.68 @volter/twin-stripe@3.0.2\nnpx volter world init --name my-app --twins stripe --source stripe=@volter/twin-stripe\n```\n\nReview the detected vendor and generated bindings before booting. Read the credential names and limitations below; the World supplies throwaway credentials. Then run your app's own command through the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nHere `npm test` is your app's existing command; replace it with your app or test command. `down` retains state.\nA later `up` resumes it; do not reset or initialize again merely to return.\n\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\n\nA Protocol 3 pack ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md)). Its surface is\ngenerated from Stripe's published OpenAPI document (`spec/`). The derived core serves plain reads, writes and deletes.\nHandlers are in `src/semantics/<family>.ts`, the state machines in `src/semantics/states.ts`, and Stripe's own\ncomputation (money and declines, billing, the ledger, the API versions) in `src/engine/`.\n\n```bash\nworld-stripe serve [--port N] [--root DIR] [--read-only]\n```\n\n## What it models\n\nWhat the demand reaches (`journeys/demand.json`: Open Autonomy, Twin, Volter Harness, and the stripe-node applications\nCal.com, Dub, Postiz, Rallly and Twenty, with their frontends' Stripe.js), the life (`journeys/customer-life.json`) and a\nvendor-backed World's refresh; each served operation is decided in `journeys/decisions.json`:\n\n- **Customers**: created, updated, searched, listed by email, deleted; their balance transactions and payment methods,\n and their active entitlements (read). Balance-transaction writes answer the gap.\n- **Catalog**: products and prices created and listed, prices retrieved, coupons and promotion codes managed. Product search and administrative product/price updates answer the gap.\n- **Checkout Sessions** and the customer portal (sessions and configurations): pay, add a card, pay an open invoice,\n cancel at the period's end or at once.\n- **Subscriptions**: created (charged at once, trialing, `default_incomplete` or `error_if_incomplete`), updated (items,\n discounts, a trial ended early or added), searched, canceled; their items, schedules (made, updated, released),\n renewals on the World clock, and a renewal declined and paid later.\n- **Invoices**: invoice items, drafts, finalize, pay (a draft is finalized on the way), void, delete, lines,\n previews and their payments. Invoice lines are read in the invoice; the standalone lines endpoint answers the gap.\n- **Intents**: payment and setup intents, confirmed on the server or by Stripe.js with the publishable key and the\n client secret, through the testing page's cards (declines, 3-D Secure) and test bank accounts (ACH debits that settle,\n micro-deposit verification asked), a hold confirmed under manual capture and canceled, a bank transfer that waits for\n funds; payment methods attached and detached; refunds (held for want of balance, with a destination charge's\n transfer reversed and its application fee refunded); the charges, disputes and Radar reviews the testing page's cards\n bring.\n- **Apps secret store**; existing Radar value lists and their items (reads and item insertion).\n- **Connect**: Express and Custom accounts, account links (Stripe's hosted onboarding) and login links, transfers (from\n a charge's funds too), payouts, the balance and its transactions, application fees and their refunds, and Connect\n OAuth (cal.com's).\n- **Issuing** (Open Autonomy's card rail): cardholders and cards (a card is `inactive` unless its create names a status;\n its number and CVC drawn from the World and shown only when expanded), activated, frozen and canceled; authorizations\n asked of the real-time endpoint, approved or declined within the window or decided by Stripe when it ends, and\n received from the vendor and closed by its transactions. Their published fixtures are recorded notReplayed because authorization creation and capture test helpers remain outside demand.\n- **Webhook endpoints** made through the API, each with its own signing secret; events listed.\n\n**Keys.** The platform's secret and publishable keys, and its webhook secret, are issued by the credential door and\nheld by their SHA-256. A request with no key, or with one Stripe never issued, is refused 401. A connected account's\nOAuth key acts as that account.\n\n**The gap.** Operations outside application demand and the declared refresh reads answer Stripe's unknown-URL 404\n(the manifest's literal `unmodeled` list). This includes administrative catalog updates and deletion, direct\nPaymentMethod creation and attachment, send-invoice, balance-credit writes, test clocks and Issuing test helpers,\ntop-ups, Plans, meter and entitlement-feature setup, Radar-list creation, and separate products such as Terminal,\nTreasury, Tax, Climate, Identity and Financial Connections. Reading an already declared resource for vendor-backed\nrefresh remains served; declaring an unused product does not establish application demand.\n\n**Vendor-backed.** Every stored resource declares its `refresh` (the list that reads it back, under its parent where it\nhas one); Stripe's webhooks are ingested by their `Stripe-Signature` (`type`, `data.object`); calls are charged against\nStripe's documented limit (25 requests a second in a sandbox).\n\n## Events\n\nEvery write Stripe reports sends its event (`payment_intent.succeeded`, `customer.subscription.created`,\n`invoice.paid`, …; a charge sends `charge.succeeded` or `charge.failed`, never an invented `charge.created`), declared as data the kernel renders, stores, signs (`Stripe-Signature: t=…,v1=…`, which the\nSDK's `constructEvent` verifies) and delivers to the account's enabled webhook endpoints whose `enabled_events` take it\n(`*`, `<family>.*` or the type). Each event is rendered in the writing request's API version.\n\n- **Connect**: an event of a connected account (a write made with its `Stripe-Account` header, its own\n `account.updated`, or a row kept on its books, such as the payout time makes for it) carries the top-level `account`\n and reaches only endpoints created with `connect=true`; the platform's reach only the others.\n- **Signing secrets in a World**: the credential door issues the application its keys and two signing secrets, its\n account's (`STRIPE_WEBHOOK_SECRET` and the other names an application reads it by) and its Connect endpoint's\n (`STRIPE_CONNECT_WEBHOOK_SECRET`), the same on every boot; an endpoint made on the Webhooks page (a door) is signed\n with the one of its kind. The twin reads no env.\n\n## Screens\n\nStripe's own pages, at their vendor urls (`src/screens/`):\n\n- **Checkout** (`checkout.stripe.com/c/pay/{session}`): the customer pays; the session completes and\n `checkout.session.completed` fires.\n- **Customer portal** (`billing.stripe.com/p/session/{session}`): cancel or renew a plan, update the card, pay an\n open invoice.\n- **Connect onboarding** (`connect.stripe.com/setup/…`): an Account Link's hosted onboarding.\n- **Connect OAuth** (`connect.stripe.com/oauth/authorize`, `/oauth/token`, `/oauth/deauthorize`; Standard accounts,\n docs.stripe.com/connect/oauth-reference). The platform's client_id is `ca_twin_self` in every World (a test\n client_id; the platform account is `acct_twin_self`), shown on the Dashboard's Connect OAuth settings page in\n `<code data-testid=\"connect-client-id\">`. OAuth starts off: a runner POSTs that page as a browser does,\n `oauth_enabled=on&redirect_uris=<one per line>`. The authorize page offers the test-mode **Skip this form** (a new\n Standard account, connected) and **Deny access**; the token endpoint exchanges a code once, within 5 minutes (a\n reused code revokes the connection), and refreshes to an equal or lesser scope; after a deauthorization the\n account's `Stripe-Account` header is refused 403 `account_invalid`. The deprecated `access_token` and\n `stripe_publishable_key` act as the connected account. Not modelled: connecting an existing Stripe account, the full\n account application, holding a `read_only` connection to reads.\n- **Stripe.js** (`js.stripe.com/v3/`, `/v3/stripe.js`, `/<release train>/stripe.js`): `redirectToCheckout({ sessionId })`\n goes to the hosted Checkout page; any other member\n throws, naming itself.\n- **Dashboard** (`dashboard.stripe.com/settings/public`, `/settings/connect/onboarding-options/oauth`): Public details\n (the business name Checkout and the portal show) and the Connect OAuth settings.\n\n## Doors\n\nThe World's hands where Stripe's API has no act (`src/semantics/doors.ts`), refused on a read-only twin:\n\n- `POST /_twin/app-credentials`: the platform's keys and webhook secret, as the runtime issues them to a World's\n applications.\n- `POST /_twin/webhook-endpoints {url, events, connect?}`: an endpoint added on the Dashboard's Webhooks page.\n- `POST /_twin/account {settings?, business_profile?, …}`: the platform's own account settings, as the Dashboard\n changes them.\n- `POST /_twin/drain`: time's events, sent when a runner drives them (`payout.paid`, `balance.available`).\n\n## Published examples\n\n`journeys/vendor-examples.json` replays Stripe's published examples for the operations the pack serves: the fixtures\nbeside its spec (`spec/fixtures3.json.gz`), and the requests and rules its documentation pages publish\n(`spec/doc-examples.json`: the testing page's cards and test bank accounts, the payment lifecycle's states, and each\nreference page's stated rule). Examples whose preconditions require an unserved setup operation are recorded notReplayed naming that operation and its pinned-spec citation. Served preconditions replay through vendor APIs, including customer balance changes and their immutable ledger entries. Coverage remains missing where no application call or published replay reaches it.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "slack",
|
|
7
|
+
"package": "@volter/twin-slack",
|
|
8
|
+
"version": "3.0.5",
|
|
9
|
+
"integrity": "sha512-P8jzf8Ss3MsXG+bc+uX9QBfYu4R74tmHgeOuSyJ8WjrsfvbJzBGZHQPGV50qUDTHD6vuh17bDqTaTsesK58aZw=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Slack twin — a faithful, stateful local Slack Web API your real Slack SDKs talk to unmodified, with its OAuth install, pages and incoming webhooks. Built on @volter/world-core.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.127"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "slack",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-slack\n\nSlack's Web API, workspace invitations and member pages, app configuration and OAuth install pages, incoming\nwebhooks and signed app deliveries. The pinned API and corrections are in spec/; provenance is spec/SOURCE.md.\nThe current product callers, operation decisions and customer story are in journeys/.\n\n## Use with an existing app\n\nIn an app that already uses Slack, install the product CLI and this exact twin release:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.127 @volter/world-core@3.0.127 @volter/twin-slack@3.0.5\nnpx volter world init --name my-app --twins slack --source slack=@volter/twin-slack\n```\n\nReview the detected vendor and bindings before booting. The World issues throwaway bot, Socket Mode and signing\ncredentials using the names listed below. Run the app's own command inside the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nReplace `npm test` with your app or test command. `down` retains state and a later `up` resumes it.\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\nThe pack models an ordinary workspace with people, channels, timestamped messages and threads, files, normal workspace\nuser groups, apps and their scoped grants. Its APIs keep Slack's ok/error envelope, cursor paging and caller visibility.\nOAuth codes and grants have their own secrets, expiry and revocation. File bytes use the kernel blob seam. Scheduled\nmessages use the World clock.\nConversation workspace identity uses Slack's `context_team_id`, including channel visibility after vendor refresh\nand shared-World cloning. Existing local rows that carry `team_id` remain readable.\n\nA person creates the workspace at slack.com/get-started and joins through invitation mail and the Join page. Workspace\nadmins manage members and invitation requests at slack.com/admin. Developers configure their app at api.slack.com/apps;\ninstallation uses slack.com/oauth/v2/authorize and oauth.v2.access. Program calls use their own issued tokens; a person's\nsynthetic client session is xoxp-<user-id>. Real credentials are never needed.\nFresh local Worlds seed a synthetic workspace named World with its owner and #general through that signup flow.\nThe default seed is copied into the application's `.volter/seeds/` by init and remains editable there. Use the CLI and core versions pinned above for this release.\n\nWorld doors represent acts the API does not perform: an externally developed distributed app (/_twin/apps), a client\nslash command, Home opening, link share or action (/_twin/client/*), and observation of app deliveries or invitation mail\n(/_twin/deliveries and /_twin/mail). The application's own credentials come from /_twin/app-credentials, which the\nWorld asks at every boot: its own app, installed in its workspace, with a bot token (`SLACK_BOT_TOKEN`), an app-level\nSocket Mode token (`SLACK_APP_TOKEN`) and the app's signing secret. It is subscribed to every event the twin sends (link_shared\naside: it names no unfurl domain) and receives them over Socket Mode (it has no Request URL); its bot holds every scope Slack's methods name. Stored vendor mutations still use the API or vendor pages.\n\nIts callers are journeys/demand.json's: RH2's Slack app and channel bridge, Volter Harness's Slack platform (the Chat\nSDK in Socket Mode), Twin's on-call recipe, Dub's Slack integration and Postiz's Slack channel. Enterprise Grid\nadministration, SCIM provisioning and legacy OAuth are outside the modeled slate. Every Web API operation no demand,\nlife step or refresh reaches answers the gap (unknown_method), files.upload among them. The upload flow is\nfiles.getUploadURLExternal, its returned byte-upload URL and files.completeUploadExternal.\n\nPublishing and catalog process: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md). Standing is the Protocol 3 grade and score-pack report, recorded after the whole\nslate is written. No result here asserts that the final walk or independent review has run.\n\nDub priority support can create a channel and send a recipient-specific Slack Connect email invitation. The stored\npending invitation is read through conversations.listConnectInvites with count/cursor pagination and retained in the\nlocal mail outbox. Receiving-workspace acceptance, approval, user-id recipients and join links are outside this\nworkflow; the twin sends no real invitation mail. Targeted invitation responses disclose no shareable URL.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "slack",
|
|
7
|
+
"package": "@volter/twin-slack",
|
|
8
|
+
"version": "3.0.4",
|
|
9
|
+
"integrity": "sha512-cYc12HiTysiGgX1sHXqTUAVe3uPSAFKfTcf761LU3SnqEmnIQmgulnRxeZb1lbTN7GDo30E2spjxqVcUdErvEw=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Slack twin — a faithful, stateful local Slack Web API your real Slack SDKs talk to unmodified, with its OAuth install, pages and incoming webhooks. Built on @volter/world-core.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.87"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "slack",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-slack\n\nSlack's Web API, workspace invitations and member pages, app configuration and OAuth install pages, incoming\nwebhooks and signed app deliveries. The pinned API and corrections are in spec/; provenance is spec/SOURCE.md.\nThe current product callers, operation decisions and customer story are in journeys/.\n\n## Use with an existing app\n\nIn an app that already uses Slack, install the product CLI and this exact twin release:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.87 @volter/twin-slack@3.0.3\nnpx volter world init --name my-app --twins slack --source slack=@volter/twin-slack\n```\n\nReview the detected vendor and bindings before booting. The World issues throwaway bot, Socket Mode and signing\ncredentials using the names listed below. Run the app's own command inside the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nReplace `npm test` with your app or test command. `down` retains state and a later `up` resumes it.\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\nThe pack models an ordinary workspace with people, channels, timestamped messages and threads, files, normal workspace\nuser groups, apps and their scoped grants. Its APIs keep Slack's ok/error envelope, cursor paging and caller visibility.\nOAuth codes and grants have their own secrets, expiry and revocation. File bytes use the kernel blob seam. Scheduled\nmessages use the World clock.\n\nA person creates the workspace at slack.com/get-started and joins through invitation mail and the Join page. Workspace\nadmins manage members and invitation requests at slack.com/admin. Developers configure their app at api.slack.com/apps;\ninstallation uses slack.com/oauth/v2/authorize and oauth.v2.access. Program calls use their own issued tokens; a person's\nsynthetic client session is xoxp-<user-id>. Real credentials are never needed.\nFresh local Worlds seed a synthetic workspace named World with its owner and #general through that signup flow.\nThe default seed is copied into the application's `.volter/seeds/` by init and remains editable there. Use `@volter/world` 3.0.88 or later, which emits the working seed runner.\n\nWorld doors represent acts the API does not perform: an externally developed distributed app (/_twin/apps), a client\nslash command, Home opening, link share or action (/_twin/client/*), and observation of app deliveries or invitation mail\n(/_twin/deliveries and /_twin/mail). The application's own credentials come from /_twin/app-credentials, which the\nWorld asks at every boot: its own app, installed in its workspace, with a bot token (`SLACK_BOT_TOKEN`), an app-level\nSocket Mode token (`SLACK_APP_TOKEN`) and the app's signing secret. It is subscribed to every event the twin sends (link_shared\naside: it names no unfurl domain) and receives them over Socket Mode (it has no Request URL); its bot holds every scope Slack's methods name. Stored vendor mutations still use the API or vendor pages.\n\nIts callers are journeys/demand.json's: RH2's Slack app and channel bridge, Volter Harness's Slack platform (the Chat\nSDK in Socket Mode), Twin's on-call recipe, Dub's Slack integration and Postiz's Slack channel. Enterprise Grid\nadministration, SCIM provisioning and legacy OAuth are outside the modeled slate. Every Web API operation no demand,\nlife step or refresh reaches answers the gap (unknown_method), files.upload among them. The upload flow is\nfiles.getUploadURLExternal, its returned byte-upload URL and files.completeUploadExternal.\n\nPublishing and catalog process: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md). Standing is the Protocol 3 grade and score-pack report, recorded after the whole\nslate is written. No result here asserts that the final walk or independent review has run.\n\nDub priority support can create a channel and send a recipient-specific Slack Connect email invitation. The stored\npending invitation is read through conversations.listConnectInvites with count/cursor pagination and retained in the\nlocal mail outbox. Receiving-workspace acceptance, approval, user-id recipients and join links are outside this\nworkflow; the twin sends no real invitation mail. Targeted invitation responses disclose no shareable URL.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "anthropic",
|
|
7
|
+
"package": "@volter/twin-anthropic",
|
|
8
|
+
"version": "1.0.3",
|
|
9
|
+
"integrity": "sha512-B7n7lnObG0nsmpkb4urtxZVixhmw4Gg1B8Xh13Oj2qj2WUulymAjpJ0sghCTdFUi+RXX/tSY43rDX1AWTJexJQ=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Anthropic Messages, streaming and tool-use workflows. Replies use configured scenarios or labeled deterministic stubs; no model runs.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.68"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "anthropic",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-anthropic\n\nA local Claude API. It serves Messages (`api.anthropic.com/v1/messages`, streamed and not), token counting and the\nmodel list, the calls Dub, Twenty, LibreChat and Claude Code make ([journeys/demand.json](./journeys/demand.json)). Around it are the Console's pages\n(`platform.claude.com`) where the API keys are made. The twin runs no model: a turn is the World's scenario's, else a\nlabeled deterministic stub.\n\n## Use with an existing app\n\nIn an app that already uses this vendor, install this exact release and the product CLI:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.68 @volter/twin-anthropic@1.0.3\nnpx volter world init --name my-app --twins anthropic --source anthropic=@volter/twin-anthropic\n```\n\nReview the detected vendor and generated bindings before booting. Read the credential names and limitations below; the World supplies throwaway credentials. Then run your app's own command through the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nHere `npm test` is your app's existing command; replace it with your app or test command. `down` retains state.\nA later `up` resumes it; do not reset or initialize again merely to return.\n\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\n\nA Protocol 3 pack ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md)). Its surface is generated\nfrom the OpenAPI document Anthropic's TypeScript SDK is generated from (`spec/`). Handlers are in\n`src/semantics/messages.ts` and `src/semantics/models.ts`, the key front in `src/semantics/around.ts`, the scenario adapter in\n`src/semantics/scenario.ts`, and pages in `src/screens`.\n\n```bash\nworld-anthropic serve [--port N] [--root DIR] [--read-only]\n```\n\n## What it models\n\n- **Keys**:\n - `Authorization: Bearer` or the legacy `x-api-key`. A missing, mistyped, disabled, deleted or expired key is `401\n authentication_error`.\n - `anthropic-version` is required.\n - Every answer carries a request id.\n- **Messages**:\n - the request checked as the API checks it (the model in the workspace catalog and released on the World clock, `max_tokens`, the thinking budget's rules,\n manual thinking refused on Claude 4.7 and later, `tool_choice` naming an offered tool);\n - the answer (`msg_…`, content blocks, `stop_reason`, `usage`) or its server-sent events: `message_start`, each\n block's start, deltas (`text_delta`, `thinking_delta` and `signature_delta`, `input_json_delta`) and stop,\n `message_delta` and `message_stop`;\n - each also as its `?beta=true` operation.\n- **The turn**: the scenario's `respond` (`text`, `toolUses`, `serverTools`, `thinking`, `stopReason`), or a stub that:\n - calls the chosen (else the first) tool while no tool result is pending;\n - answers a value the structured output's schema admits (`output_config.format`, or the beta's `output_format`);\n - otherwise echoes the last message, labeled.\n- **Tokens**: text at four characters a token, an image at `⌈width/28⌉ × ⌈height/28⌉` visual tokens (read from a PNG's\n or JPEG's header, at most the model's limit). Token counting (`?beta=true`, as Claude Code sends it) answers the same count with no message made.\n- **The prompt cache**, per workspace:\n - a prefix per `cache_control` breakpoint, in the order tools, system, messages;\n - written with its lifetime (5 minutes, or 1 hour) and read while live, each read refreshing it;\n - a prefix under the model's minimum is not cached.\n - `usage` reports `cache_creation_input_tokens`, `cache_read_input_tokens` and `cache_creation`.\n- **Models**: `GET /v1/models`, the models an organization can use, newest first, paged by `after_id`/`before_id`,\n each released by the World clock, with its limits, thinking and effort as its documentation page states them.\n- **The Console**: sign-in by an emailed code; the API keys page (create with an expiration, shown once; disable,\n re-enable, delete).\n\nA scenario's `toolUses` is an array of `{ name, input }` calls; `thinking` is a string. For synthetic web search,\n`serverTools` is an array of `{ name: \"web_search\", input: { query: \"...\" }, results: [...] }`. Each result has\n`type: \"web_search_result\"`, `url`, `title`, `encrypted_content` and optional `page_age`. These scripts describe\nlocal fixture output and must match a tool the request offers; tool choice and parallel-use restrictions still apply.\n\n## Doors\n\n- `POST /_twin/users/{email} {organization}`: a person's sign-up, admin of a new organization and its Default workspace.\n- `GET /_twin/mailbox/{email}`: the mail the Console sent them.\n- `POST /_twin/api-keys {email, organization?, name?}`: issue a workspace key without driving the incidental Console.\n- `POST /_twin/app-credentials {}`: issue or resume the World application's key.\n\n## Not yet\n\nMessage Batches, Files, Skills, Managed Agents, the Admin API, the non-beta token count and the other beta surfaces:\nno application calls them. Web search can be scripted as synthetic server_tool_use/web_search_tool_result blocks using respond.serverTools; no hosted search runs. Unconfigured hosted tools, code execution and trusted-access Mythos models answer the documented error class.\n\nThe Console pages model only credential setup and revocation already required by the customer life. The served API is stateless; Console setup stays local and this pack has no vendor-backed deploy or refresh. The product's core work is its API; this pack adds no chat or generation dashboard. Text token counts and signatures are deterministic local approximations, not a tokenizer or valid model-generated reasoning.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "supabase",
|
|
7
|
+
"package": "@volter/twin-supabase",
|
|
8
|
+
"version": "1.0.3",
|
|
9
|
+
"integrity": "sha512-UO5MsMinW6IeZhG92HewkmYVhlM6I4lH8EWMOhNks5Dax0IUQjYJPWdPo9TSqXj0IzDI7luE2nge+p1+5F9Fjw=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Supabase twin: a project's Postgres database, the World's own managed Postgres, whose URL the twin hands the application; the Management API, PostgREST, Storage and Auth answer the gap. Built on @volter/world-core.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.92"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "supabase",
|
|
21
|
+
"bugs": null
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-supabase\n\nA local Supabase project's **Postgres database**: in a World it is the World's own managed Postgres, and the twin hands\nthe application its URL. A Protocol 3 derived pack (twin-world's\narchitecture, \"Protocol 3: the derived pack\"); no real Supabase is contacted.\n\nInstall the exact twin and World CLI in your app:\n\n```sh\nnpm install --save-dev --save-exact @volter/world@3.0.92 @volter/twin-supabase@1.0.3\n```\n\nFollow [Run a full stack](https://github.com/volter-ai/twin-world/blob/main/docs/guides/run-a-full-stack.md#a-real-database)\nto configure the World-owned Postgres and run your migrations and app inside the World. Keep your native Postgres\nclient unchanged. This release does not implement Supabase's HTTP APIs or make supabase-js calls work.\n\nFor an operator calling the server directly:\n\n```sh\nbun run src/cli.ts serve --database <postgres url> # without --database the project has no database to hand out (503)\n```\n\n## For whom\n\nRH2 (Volter's product), whose authority store is a Supabase project's Postgres, reached over the Postgres wire alone:\n\"no PostgREST, no Supabase client library, no anon session\" (`journeys/demand.json`). Its release migrates the database\nand its Worker queries it; both are answered by Postgres itself, the World's database (`journeys/customer-life.json`\nwalks RH2's own statements on it).\n\n## What is served\n\n- **The database.** The runtime binds the twin to the World's managed Postgres (`managedDatabase`: `serve --database\n <url>`), and the application connects to that database with any Postgres client. Under the containerless backing its\n clock follows the World clock. Database-generated randomness belongs to the backing and is not pinned; use explicit\n stable fixture IDs when comparing fresh Worlds (twin-world architecture, SQL steps).\n- **The door.** `POST /_twin/app-credentials` (the descriptor's `credentialDoor`, called by the runtime at every boot):\n makes the World's project `world` the first time and answers `{ ref, database_url }`, filling `SUPABASE_DB_URL`.\n- **Not served** (the gap): every operation of the Management API (`api.supabase.com/v1`), PostgREST (`/rest/v1`),\n Storage (`/storage/v1`) and Auth (`/auth/v1`), each answering its unit's own unknown-route error\n (`journeys/decisions.json`); Realtime and Edge Functions (their paths are not claimed, so the injector refuses them).\n\n## Units\n\n| Unit | Spec | Serves |\n|---|---|---|\n| `supabase` (`src/`) | `spec/openapi.json.gz`, api.supabase.com's own document (170 operations) | the door; the Management API is the gap |\n| `supabase/rest` | `rest/spec/client-ops.json`, the calls `@supabase/postgrest-js` makes | the gap |\n| `supabase/storage` | `storage/spec/openapi.json`, storage-api's document as Supabase's docs publish it | the gap |\n| `supabase/auth` | `auth/spec/openapi.yaml`, GoTrue v2.197.0's document | the gap |\n\n## Evidence\n\nThe vendor's documents and recordings are under each unit's `spec/` (its `SOURCE.md`).\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "slack",
|
|
7
|
+
"package": "@volter/twin-slack",
|
|
8
|
+
"version": "3.0.3",
|
|
9
|
+
"integrity": "sha512-KXepCGDooRc7u6QRU9nwoFJ8oeC8Fg16MoTn9YiIqissQsGUvAoCZ0Zs39qvq/wq3m+pmjVtsvv7a2fPd6aOtg=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Slack twin — a faithful, stateful local Slack Web API your real Slack SDKs talk to unmodified, with its OAuth install, pages and incoming webhooks. Built on @volter/world-core.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.87"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "slack",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-slack\n\nSlack's Web API, workspace invitations and member pages, app configuration and OAuth install pages, incoming\nwebhooks and signed app deliveries. The pinned API and corrections are in spec/; provenance is spec/SOURCE.md.\nThe current product callers, operation decisions and customer story are in journeys/.\n\n## Use with an existing app\n\nIn an app that already uses Slack, install the product CLI and this exact twin release:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.87 @volter/twin-slack@3.0.3\nnpx volter world init --name my-app --twins slack --source slack=@volter/twin-slack\n```\n\nReview the detected vendor and bindings before booting. The World issues throwaway bot, Socket Mode and signing\ncredentials using the names listed below. Run the app's own command inside the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nReplace `npm test` with your app or test command. `down` retains state and a later `up` resumes it.\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\nThe pack models an ordinary workspace with people, channels, timestamped messages and threads, files, normal workspace\nuser groups, apps and their scoped grants. Its APIs keep Slack's ok/error envelope, cursor paging and caller visibility.\nOAuth codes and grants have their own secrets, expiry and revocation. File bytes use the kernel blob seam. Scheduled\nmessages use the World clock.\n\nA person creates the workspace at slack.com/get-started and joins through invitation mail and the Join page. Workspace\nadmins manage members and invitation requests at slack.com/admin. Developers configure their app at api.slack.com/apps;\ninstallation uses slack.com/oauth/v2/authorize and oauth.v2.access. Program calls use their own issued tokens; a person's\nsynthetic client session is xoxp-<user-id>. Real credentials are never needed.\n\nWorld doors represent acts the API does not perform: an externally developed distributed app (/_twin/apps), a client\nslash command, Home opening, link share or action (/_twin/client/*), and observation of app deliveries or invitation mail\n(/_twin/deliveries and /_twin/mail). The application's own credentials come from /_twin/app-credentials, which the\nWorld asks at every boot: its own app, installed in its workspace, with a bot token (`SLACK_BOT_TOKEN`), an app-level\nSocket Mode token (`SLACK_APP_TOKEN`) and the app's signing secret. It is subscribed to every event the twin sends (link_shared\naside: it names no unfurl domain) and receives them over Socket Mode (it has no Request URL); its bot holds every scope Slack's methods name. Stored vendor mutations still use the API or vendor pages.\n\nIts callers are journeys/demand.json's: RH2's Slack app and channel bridge, Volter Harness's Slack platform (the Chat\nSDK in Socket Mode), Twin's on-call recipe, Dub's Slack integration and Postiz's Slack channel. Enterprise Grid\nadministration, SCIM provisioning and legacy OAuth are outside the modeled slate. Every Web API operation no demand,\nlife step or refresh reaches answers the gap (unknown_method), files.upload among them. The upload flow is\nfiles.getUploadURLExternal, its returned byte-upload URL and files.completeUploadExternal.\n\nPublishing and catalog process: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md). Standing is the Protocol 3 grade and score-pack report, recorded after the whole\nslate is written. No result here asserts that the final walk or independent review has run.\n\nDub priority support can create a channel and send a recipient-specific Slack Connect email invitation. The stored\npending invitation is read through conversations.listConnectInvites with count/cursor pagination and retained in the\nlocal mail outbox. Receiving-workspace acceptance, approval, user-id recipients and join links are outside this\nworkflow; the twin sends no real invitation mail. Targeted invitation responses disclose no shareable URL.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "github",
|
|
7
|
+
"package": "@volter/twin-github",
|
|
8
|
+
"version": "3.0.5",
|
|
9
|
+
"integrity": "sha512-uoGcRonDjul+8ITbYnSFanDzaQUMdFuLb2IWSTgydvIVuSeA1dato358ST5cjv/nelMgrRi3yr9fyUklw+Fh7A=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local GitHub repository, issue, pull-request and git workflows over shared synthetic state. REST, GraphQL and Actions scope is documented in the README.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.68"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "github",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-github\n\nA local GitHub: the REST API the unmodified `@octokit/rest` and `gh` call (`https://api.github.com`), the GraphQL API\nbeside it, git over smart HTTP, and the github.com pages an application sends a person through, over one state.\n\n## Use with an existing app\n\nIn an app that already uses this vendor, install this exact release and the product CLI:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.68 @volter/twin-github@3.0.5\nnpx volter world init --name my-app --twins github --source github=@volter/twin-github\n```\n\nReview the detected vendor and generated bindings before booting. Read the credential names and limitations below; the World supplies throwaway credentials. Then run your app's own command through the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nHere `npm test` is your app's existing command; replace it with your app or test command. `down` retains state.\nA later `up` resumes it; do not reset or initialize again merely to return.\n\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\n\nA Protocol 3 derived pack ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md)): the REST surface is generated from GitHub's published OpenAPI description and the GraphQL schema beside it\n(`spec/`), plain reads and updates are the derived core's, the state machines are `src/semantics/states.ts`,\nhandlers by operationId (`src/semantics/<family>.ts`) serve only what an operation does beyond them, the GraphQL\nresolvers are `src/semantics/graphql.ts`, and GitHub's own computation (workflow files, advisories, a README's\nMarkdown, TOTP, a CVSS vector's score) is `src/engine/`. It serves what the applications call and what one customer's\nlife sends ([journeys/demand.json](./journeys/demand.json), [journeys/decisions.json](./journeys/decisions.json),\n[journeys/customer-life.json](./journeys/customer-life.json)); every other operation answers GitHub's own 404, and every\nother GraphQL root field GraphQL's undefinedField. GitHub's published examples for the operations served, and the rules\nits pages state, are replayed in [journeys/vendor-examples.json](./journeys/vendor-examples.json)\n([spec/doc-examples.json](./spec/doc-examples.json)).\n\n```bash\nworld-github serve [--port N] [--root DIR] [--read-only]\n```\n\nPoint a client at it (`new Octokit({ baseUrl })`, `GH_HOST`), or run the application in a World, whose routing sends\n`api.github.com`, `github.com` (its sign-in, settings and app pages and git), `uploads.github.com`,\n`raw.githubusercontent.com` and `token.actions.githubusercontent.com` here.\n\n## What it models\n\n- **Who it is for**: Volter's own products (Open Autonomy's kit, setup and platform, the Volter Harness board and\n installer, the Volter Editor, Workbench's store, Twin's World action, Actions runner, catalog release and on-call\n recipe, Volter identity's sign-in), Dub's GitHub sign-in, Rallly's update check and Twenty's site; the opt-in GitHub\n features of LibreChat, Postiz and Twenty are listed apart (`demand.json`'s `optional`).\n- **Repositories**: made by GraphQL `createRepository` (as `gh repo create` makes them), read with the caller's\n `permissions`, their README (and its HTML), contents committed through the API; rulesets, enforced on pushes,\n contents commits and merges; environments with their branch policies and secrets, repository variables and secrets\n (sealed to the repository's key), deploy keys; teams and their repositories.\n- **Git**: smart HTTP clone, fetch and push at `github.com/<owner>/<repo>.git`, contents, commits, compares, trees,\n blobs, refs and annotated tags read from the same objects, abbreviated SHAs resolved; a push a ruleset refuses is\n refused as GitHub refuses it (GH013).\n- **Issues and pull requests**: issues (read one by its number, as Octokit's `issues.get`), labels, milestones and\n comments; pull requests from branches of the repository, their reviews, and merges (GraphQL `mergePullRequest`, and\n REST's merge, squash or rebase) that close the issues their bodies name; a pull request closes with its deleted head\n branch.\n- **Releases, statuses, webhooks and advisories**: releases with uploaded assets, commit statuses, a repository's\n webhooks and their deliveries, repository security advisories (made and published).\n- **Actions, as the World's runner works it**: a push starts the workflows of its commit; the runner (twin-world's\n `volter-world-actions-runner`) finds its repositories and their queued runs, starts one through the World's door\n with its job token, the repository's secrets (sealed to its key) and variables and an OIDC request, and completes it\n with its jobs' conclusions and artifacts; the OIDC provider (`token.actions.githubusercontent.com`) signs the job's\n token, which Sigstore's Fulcio twin verifies.\n- **Apps**: GitHub Apps from a manifest or the World's door, installed from their installation page, their JWT, a\n repository's installation and its installation tokens (narrowed to permissions and repositories).\n- **Sign-in**: github.com's password and two-factor pages, OAuth apps' web flow, GitHub Apps' user tokens and\n refresh tokens (a refresh needs no secret and revokes the access token it replaces), and the device flow\n `gh auth login` runs.\n- **GraphQL**: `repository` with what Open Autonomy's community desk and `gh pr create`, `gh pr view` and `gh pr merge`\n read (its owner, default branch, the caller's permission, its parent, its discussions and their categories, its pull\n requests by branch with their commits' status rollup, review decision and merge state), the schema's own\n introspection, and the mutations they send: `createRepository`, `createDiscussion`, `addDiscussionComment`,\n `createPullRequest` and `mergePullRequest`.\n\n## Events\n\nA write GitHub reports sends its webhook (`issues`, `pull_request`, `push`, `installation`, …), declared as data the\nkernel renders, signs (`X-Hub-Signature-256`, and the SHA-1 `X-Hub-Signature`) and delivers: to the repository's and\nits organization's hooks whose events take it, and to each GitHub App whose installation covers the repository, with\nthe installation in the payload. A hook's deliveries are `GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries`.\n\n**Vendor-backed.** Each stored resource reads back by its list (under its repository, `{owner}/{repo}`) but installations,\nwhich only an App's own credentials list, GitHub's\nwebhooks are ingested by `X-Hub-Signature-256` (each event's object at its own key, its repository by\n`repository.full_name`; a push is acknowledged and folds nothing), and calls are charged against GitHub's documented\nlimits (5,000 an hour, 900 points a minute).\n\n## Doors\n\nWhat happens outside the API is the World's door (`/_twin/…`, declared in the manifest): signing up, choosing a\npassword, turning on two-factor authentication and reading the authenticator's code, making a personal access token,\nan organization, a GitHub App or an OAuth app, and a runner starting and completing a workflow run.\n\n## What it leaves out\n\nEvery operation no in-scope application and no life step reaches: the manifest's `unmodeled` (the rest of Actions,\nPages, deployments, attestations, Dependabot and code scanning, Projects, search, forks, transfers, branch\nprotection, issue locks), the GraphQL root fields beyond `repository` and the five mutations, and the browser\ndownload of a release's `latest` asset, which `install.sh` fetches. Where GitHub documents more than the twin does, the\ntwin does less: a rebase merge is one commit, a CVSS 4.0 vector is not scored, and a pull request's head is a branch of\nits own repository. Its standing is twin-packs-p3's generated `STANDING.md`.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "linear",
|
|
7
|
+
"package": "@volter/twin-linear",
|
|
8
|
+
"version": "3.0.3",
|
|
9
|
+
"integrity": "sha512-3V84nwtDUtwgyZOXzclEZMCZqjEeidbSH32okOm+pUk6z9RqaSHJN87gVdXJht8UYh3sUnr2fYiCA1mK2w75Uw=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Protocol 3 Linear twin for the official SDK viewer, team and issue workflow and the documented issue-filing integration.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.105"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "linear",
|
|
21
|
+
"bugs": null
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-linear\n\nA Protocol 3 Linear twin for a workspace’s issue-filing integration and the Linear SDK\ninstalled by Twin ([demand](./journeys/demand.json)). It serves Linear’s GraphQL endpoint,\nOAuth authorization-code installation, token refresh and configured client-credentials grants,\nworkspace/team/project discovery,\nworkflow states, issue creation/update/archive, labels and comments. The customer life and\npublished-example journey define the modeled scope ([decisions](./journeys/decisions.json)).\n\nResources are read back with declared GraphQL refresh queries, including archived issues.\nMutation deployment uses the vendored schema to adopt the resource returned by Linear.\nRefresh-token retries preserve the returned pair during Linear’s documented 30-minute grace.\nThe executor budget stays below the documented API-key request quota.\n\nThe World’s doors represent settings/UI actions Linear’s API does not expose:\n`POST /_twin/workspaces`, `POST /_twin/workspaces/{urlKey}/people`,\n`POST /_twin/app-credentials` and `POST /_twin/api-keys`. The local credential door\n`POST /_twin/local-credentials` uses those same settings actions to make an idempotent synthetic\nstarter workspace/owner, issue its personal key and register a World OAuth client. It supplies\n`LINEAR_API_KEY`, `LINEAR_CLIENT_ID` and `LINEAR_CLIENT_SECRET`; the personal key names a stored\nowner and is retained across stop/resume. Teams and projects are created through the\nvendor API. The authorize screen uses the registered callback and carries its state back.\n\nThe published relation, logical, date, label, comment, estimate and project-lead filters are served.\nOther GraphQL fields, private-team access management, webhook configuration, PKCE and OAuth\nrevocation are outside this modeled scope and are refused. The SDK’s default\nviewer, team and issue selections are modeled for the official SDK 86.0.0's create/update/read flow\nin [the installed customer entry](./journeys/first-use.json). This does not claim every SDK method.\nNo webhook subscription is made by this life;\nthere is no invented webhook delivery. Release assessments are retained by\n[the independent catalog](https://github.com/volter-ai/twin-catalog-open).\n\nInstall the selected release in your app with `npm install --save-dev @volter/twin-linear@3.0.3`.\nThe app keeps its real `@linear/sdk`; the packaged customer entry pins 86.0.0.\nFor local setup, use the app folder’s `volter world init`, review the detected vendors,\nand keep Linear when the app needs it. Start with `volter world up`, run the app or seed\nthrough `volter world run -- <command>`, and stop with `volter world down`. The World’s\n`GET /twin` describes identity, time, and the available doors.\n\nThe workspace door takes `{ \"name\": \"Example\", \"urlKey\": \"example\", \"owner\": { \"name\": \"Ada\", \"email\": \"ada@example.invalid\", \"password\": \"example-password\" } }`.\nThe people door takes `{ \"name\", \"email\", \"password\" }`; the key door takes `{ \"email\", \"label\" }`.\nThe app door takes `{ \"name\", \"redirect_uris\": [\"https://app.example/callback\"] }`;\nits optional `client_credentials: { workspace: \"example\", teamIds: [...] }` represents\nthe settings toggle and the app user’s configured team access. All credentials are synthetic.\n\nProfiles, public-team settings, empty optional-feature state, issue relations and counts are stored\nin their vendor response shapes and preserved by the declared refresh queries. `isMe` is resolved\nfor the current caller. Creator counts include archived issues; team counts exclude them unless\n`includeArchived: true` is requested. The kernel maintains these counters on recorded writes.\nThe starter leaves cycles, triage, integrations, sharing and automation unconfigured. Its inactive\nnumeric settings, avatar colors, invitation hashes, app actor email addresses and branch naming are\nexplicitly synthetic choices where upstream documentation does not declare production defaults.\nMutations for those additional features remain outside scope; absent feature state does not claim\nthat their behavior is implemented.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "github",
|
|
7
|
+
"package": "@volter/twin-github",
|
|
8
|
+
"version": "3.0.6",
|
|
9
|
+
"integrity": "sha512-NNv6Lc3XWjNTqT2l/I+ha8wcnO/7kDtI8+oybYvbngxL389iQc99MvrSIdcdv9AkISrcvIvd8SiQpfsDu16V7w=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local GitHub repository, issue, pull-request and git workflows over shared synthetic state. REST, GraphQL and Actions scope is documented in the README.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.127"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "github",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-github\n\nA local GitHub: the REST API the unmodified `@octokit/rest` and `gh` call (`https://api.github.com`), the GraphQL API\nbeside it, git over smart HTTP, and the github.com pages an application sends a person through, over one state.\n\n## Use with an existing app\n\nIn an app that already uses this vendor, install this exact release and the product CLI:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.127 @volter/twin-github@3.0.6\nnpx volter world init --name my-app --twins github --source github=@volter/twin-github\n```\n\nReview the detected vendor and generated bindings before booting. Read the credential names and limitations below; the World supplies throwaway credentials. Then run your app's own command through the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nHere `npm test` is your app's existing command; replace it with your app or test command. `down` retains state.\nA later `up` resumes it; do not reset or initialize again merely to return.\n\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\n\nA Protocol 3 derived pack ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md)): the REST surface is generated from GitHub's published OpenAPI description and the GraphQL schema beside it\n(`spec/`), plain reads and updates are the derived core's, the state machines are `src/semantics/states.ts`,\nhandlers by operationId (`src/semantics/<family>.ts`) serve only what an operation does beyond them, the GraphQL\nresolvers are `src/semantics/graphql.ts`, and GitHub's own computation (workflow files, advisories, a README's\nMarkdown, TOTP, a CVSS vector's score) is `src/engine/`. It serves what the applications call and what one customer's\nlife sends ([journeys/demand.json](./journeys/demand.json), [journeys/decisions.json](./journeys/decisions.json),\n[journeys/customer-life.json](./journeys/customer-life.json)); every other operation answers GitHub's own 404, and every\nother GraphQL root field GraphQL's undefinedField. GitHub's published examples for the operations served, and the rules\nits pages state, are replayed in [journeys/vendor-examples.json](./journeys/vendor-examples.json)\n([spec/doc-examples.json](./spec/doc-examples.json)).\n\n```bash\nworld-github serve [--port N] [--root DIR] [--read-only]\n```\n\nPoint a client at it (`new Octokit({ baseUrl })`, `GH_HOST`), or run the application in a World, whose routing sends\n`api.github.com`, `github.com` (its sign-in, settings and app pages and git), `uploads.github.com`,\n`raw.githubusercontent.com` and `token.actions.githubusercontent.com` here.\n\n## What it models\n\n- **Who it is for**: Volter's own products (Open Autonomy's kit, setup and platform, the Volter Harness board and\n installer, the Volter Editor, Workbench's store, Twin's World action, Actions runner, catalog release and on-call\n recipe, Volter identity's sign-in), Dub's GitHub sign-in, Rallly's update check and Twenty's site; the opt-in GitHub\n features of LibreChat, Postiz and Twenty are listed apart (`demand.json`'s `optional`).\n- **Repositories**: made by GraphQL `createRepository` (as `gh repo create` makes them), read with the caller's\n `permissions`, their README (and its HTML), contents committed through the API; rulesets, enforced on pushes,\n contents commits and merges; environments with their branch policies and secrets, repository variables and secrets\n (sealed to the repository's key), deploy keys; teams and their repositories.\n- **Git**: smart HTTP clone, fetch and push at `github.com/<owner>/<repo>.git`, contents, commits, compares, trees,\n blobs, refs and annotated tags read from the same objects, abbreviated SHAs resolved; a push a ruleset refuses is\n refused as GitHub refuses it (GH013).\n- **Issues and pull requests**: issues (read one by its number, as Octokit's `issues.get`), labels, milestones and\n comments; pull requests from branches of the repository, their reviews, and merges (GraphQL `mergePullRequest`, and\n REST's merge, squash or rebase) that close the issues their bodies name; a pull request closes with its deleted head\n branch.\n- **Releases, statuses, webhooks and advisories**: releases with uploaded assets, commit statuses, a repository's\n webhooks and their deliveries, repository security advisories (made and published).\n- **Actions, as the World's runner works it**: a push starts the workflows of its commit; the runner (twin-world's\n `volter-world-actions-runner`) finds its repositories and their queued runs, starts one through the World's door\n with its job token, the repository's secrets (sealed to its key) and variables and an OIDC request, and completes it\n with its jobs' conclusions and artifacts; the OIDC provider (`token.actions.githubusercontent.com`) signs the job's\n token, which Sigstore's Fulcio twin verifies.\n- **Apps**: GitHub Apps from a manifest or the World's door, installed from their installation page, their JWT, a\n repository's installation and its installation tokens (narrowed to permissions and repositories).\n- **Sign-in**: github.com's password and two-factor pages, OAuth apps' web flow, GitHub Apps' user tokens and\n refresh tokens (a refresh needs no secret and revokes the access token it replaces), and the device flow\n `gh auth login` runs.\n- **GraphQL**: `repository` with what Open Autonomy's community desk and `gh pr create`, `gh pr view` and `gh pr merge`\n read (its owner, default branch, the caller's permission, its parent, its discussions and their categories, its pull\n requests by branch with their commits' status rollup, review decision and merge state), the schema's own\n introspection, and the mutations they send: `createRepository`, `createDiscussion`, `addDiscussionComment`,\n `createPullRequest` and `mergePullRequest`.\n\n## Events\n\nA write GitHub reports sends its webhook (`issues`, `pull_request`, `push`, `installation`, …), declared as data the\nkernel renders, signs (`X-Hub-Signature-256`, and the SHA-1 `X-Hub-Signature`) and delivers: to the repository's and\nits organization's hooks whose events take it, and to each GitHub App whose installation covers the repository, with\nthe installation in the payload. A hook's deliveries are `GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries`.\n\n**Vendor-backed.** Each stored resource reads back by its list (under its repository, `{owner}/{repo}`) but installations,\nwhich only an App's own credentials list, GitHub's\nwebhooks are ingested by `X-Hub-Signature-256` (each event's object at its own key, its repository by\n`repository.full_name`; a push is acknowledged and folds nothing), and calls are charged against GitHub's documented\nlimits (5,000 an hour, 900 points a minute).\n\n## Doors\n\nWhat happens outside the API is the World's door (`/_twin/…`, declared in the manifest): signing up, choosing a\npassword, turning on two-factor authentication and reading the authenticator's code, making a personal access token,\nan organization, a GitHub App or an OAuth app, and a runner starting and completing a workflow run.\n\n## What it leaves out\n\nEvery operation no in-scope application and no life step reaches: the manifest's `unmodeled` (the rest of Actions,\nPages, deployments, attestations, Dependabot and code scanning, Projects, search, forks, transfers, branch\nprotection, issue locks), the GraphQL root fields beyond `repository` and the five mutations, and the browser\ndownload of a release's `latest` asset, which `install.sh` fetches. Where GitHub documents more than the twin does, the\ntwin does less: a rebase merge is one commit, a CVSS 4.0 vector is not scored, and a pull request's head is a branch of\nits own repository. Its standing is twin-packs-p3's generated `STANDING.md`.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "openai",
|
|
7
|
+
"package": "@volter/twin-openai",
|
|
8
|
+
"version": "3.0.2",
|
|
9
|
+
"integrity": "sha512-DbNSre3DPt6mY1VKRX9Tdevl2Gg0l2vi9Jx7FGH23Xl3WEV+tWCyiUMDSDc8uoCBT0p1VUR7xz8svjRDukDORw=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local OpenAI Responses, Chat Completions and tool-use workflows. Replies use configured scenarios or labeled deterministic stubs; no model runs.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.87"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "openai",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-openai\n\nA local OpenAI API. It serves the calls the applications make (`journeys/demand.json`):\n\n## Use with an existing app\n\nIn an app that already uses this vendor, install this exact release and the product CLI:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.92 @volter/twin-openai@3.0.2\nnpx volter world init --name my-app --twins openai --source openai=@volter/twin-openai\n```\n\nReview the detected vendor and generated bindings before booting. Read the credential names and limitations below; the World supplies throwaway credentials. Then run your app's own command through the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nHere `npm test` is your app's existing command; replace it with your app or test command. `down` retains state.\nA later `up` resumes it; do not reset or initialize again merely to return.\n\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\n\n- the Responses API (Twenty, Rallly, Postiz and LibreChat, through the AI SDK's OpenAI provider and the openai SDK);\n- Chat Completions (Workbench's agent, the on-call cookbook, Postiz, LibreChat), the models list, Files, Images (generations\n and edits), moderations, transcriptions and text to speech;\n- LibreChat's Assistants v2: assistants, threads, messages, runs and their steps and tool outputs.\n\nAround it are the dashboard pages (`platform.openai.com`: the log in and a project's API keys). The twin runs no model:\na turn is the World's scenario's, else a deterministic stub labeled `[twin-stub:<model>]`.\n\nA Protocol 3 pack ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md)). Its surface is generated\nfrom OpenAI's published OpenAPI document (`spec/`). The derived core serves plain reads and writes. Handlers are in\n`src/semantics/<family>.ts`, the scenario adapter in `src/semantics/scenario.ts`, and pages in `src/screens`.\n\n```bash\nworld-openai serve [--port N] [--root DIR] [--read-only]\n```\n\n## What it models\n\n- **Keys**:\n - A project key is made on the project's API keys page (shown once, held by its SHA-256), or issued to a World's\n applications by the credential door.\n - A request with no key, or one the organization never made, is refused 401 `invalid_api_key`. So is a revoked key,\n or one of an archived project.\n- **Responses**:\n - `POST /v1/responses`, streamed (named events, ending with `response.completed`) or not.\n - Function tools the stub calls while no tool output is pending; `previous_response_id` carrying the conversation.\n - Structured output (`text.format` with a JSON schema) the stub answers with a value the schema admits.\n- **Chat Completions**: the answer or its `chat.completion.chunk` stream ending with `[DONE]`, and tool calls.\n- **Assistants v2**:\n - A run is worked when a read first looks at it.\n - A run with function tools stops at `requires_action` for their outputs, then completes with a stub reply. A run\n in flight can be cancelled. A run still waiting on its outputs at its `expires_at`, ten minutes after it was\n created, expires and refuses them.\n - The thread's messages and the run's steps are kept.\n- **Files**: uploaded (multipart), read, downloaded, deleted. Missing locally held bytes are refused; refreshed file metadata does not supply content.\n- **Images**: `POST /v1/images/generations` and `POST /v1/images/edits` answer a labeled placeholder image. DALL-E default URLs serve those bytes through the media lane for 60 minutes.\n- **Moderations**: `POST /v1/moderations` classifies each input deterministically: text naming a category's own words is\n flagged in it, with its categories and scores; no model runs.\n- **Speech**: `POST /v1/audio/speech` answers an audio file in the format asked (mp3 unless named), billed by the\n characters it reads.\n- **Transcriptions**: `POST /v1/audio/transcriptions` answers a labeled stub transcript, with the WAV duration from its header; other formats use a synthetic one-second duration.\n- **Models**: a static catalog.\n- **Realtime**: `wss://api.openai.com/v1/realtime` (Volter Harness's voice): every client event the reference lists: the\n session, the input audio buffer (append, commit, clear; no speech is detected in it), conversation items (create,\n retrieve, truncate, delete) and responses as events; `output_audio_buffer.clear`, WebRTC's and SIP's, is refused on the\n WebSocket. A response is the World's scenario's turn, else the labeled stub, spoken as silence with its transcript.\n\nThe subscription surface serves Open Autonomy, RH2, Browser Substrate and Volter Harness. On `auth.openai.com` it supplies browser consent with localhost callback, state and S256 PKCE, device user-code polling, authorization-code exchange, refresh and revocation. On `chatgpt.com/backend-api/codex` it serves Responses over HTTP/SSE and WebSocket, compaction and per-account model discovery. The native TUI’s `/backend-api/wham` usage, token activity, workspace-message and reset-credit views use a synthetic Plus account with no purchased credits. Account limits and expiry are explicit local policy where the private documentation gives no number. HTTP and socket model turns use configured scenarios or labeled deterministic stubs.\n\n## Doors\n\n- `POST /_twin/accounts {email, name, password, role?}`: a person of the World's organization, who logs in to the\n dashboard.\n- `POST /_twin/app-credentials`: the Default project and a key for it, as the runtime issues them to a World's\n applications. It also issues the World’s synthetic subscription account and signed tokens; `CODEX_HOME` is filled with a private directory containing Codex’s `auth.json` and file-storage config. The hosted browser/device pages accept the door’s `codex_email` and `codex_password`. No production account or key is used.\n\n## Not yet\n\nEmbeddings, fine-tuning, batches, uploads, evals, containers and the Admin API answer the documented gap.\nVector stores supply the empty store and its readbacks that the published file-search examples require; the twin\nperforms no embedding or retrieval. Stored chat completions and Responses support their published readbacks.\nThe dashboard is limited to credential issuance; model calls are the product surface.\n\nUndemanded private cloud tasks, remote configuration, account checks and workspace policy settings answer HTTP 404 in the pinned client’s accepted error envelope. Native cloud commands, remote control and experimental voice/plugin flows are outside these products’ configured subscription runtime; independently demanded REST and Realtime calls are described above.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "upstash",
|
|
7
|
+
"package": "@volter/twin-upstash",
|
|
8
|
+
"version": "1.0.1",
|
|
9
|
+
"integrity": "sha512-/0qbzpyAMt+lRa5Cl4+hgCRCGH5fSxWiD0bY4Haj5yZD6Y4W+67LQRllb5wUiYsqkSE33HOn5nbkvzUwMix9JA=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Deterministic Upstash Redis over REST, rate-limit client calls, and QStash workflows; no live Upstash calls.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.68"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "upstash",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-upstash\n\nA local Upstash: Redis over Upstash's REST API, the one the unmodified `@upstash/redis` and `@upstash/ratelimit` call\n(`https://<endpoint>.upstash.io`, this unit), the console where a database and QStash's credentials are made\n(`console.upstash.com`, the `api/` lane, beside the Developer API's spec), and QStash with Workflow\n(`https://qstash[-<region>].upstash.io`, the `qstash/` lane), over one vendor state.\n\n## Use with an existing app\n\nFor an app using the supported Redis REST or QStash workflows, install the exact release:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.68 @volter/twin-upstash@1.0.1\nnpx volter world init --name my-app --twins upstash --source upstash=@volter/twin-upstash\n```\n\nReview the detected vendor and generated bindings before booting. The World supplies throwaway credentials;\nseed stored data through the unchanged vendor SDK, then run your app's existing test command inside the World.\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nUse your app's test command in place of `npm test`. Ordinary `down` retains state for the next `up`.\n\n\nA Protocol 3 pack ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md)). The Redis\nunit's surface is Redis's command table (`spec/commands`), and its front (`src/semantics/around.ts`) reads Upstash's REST\nforms and runs the commands with the kernel's Redis core under Upstash's dialect (`src/semantics/shared.ts`). Each lane's\nsurface is generated from its own spec, with handlers in `<lane>/src/semantics/<family>.ts` and state machines in\n`<lane>/src/semantics/states.ts`.\n\n```bash\nworld-upstash serve [--port N] [--root DIR] [--read-only]\n```\n\n## The World's Upstash\n\nA person signs in to the console and creates a Redis database there (name, primary region, the free plan). The\ndatabase's page shows `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN` and the Read Only token. On a first visit to\nQStash they pick a region; the page then shows `QSTASH_URL`, `QSTASH_TOKEN` and the two signing keys, and can reset the\ntoken and roll the keys.\n\n## What it models\n\n- **Redis over REST**: a command in the path (`/set/foo/bar`, a POST body as its last argument) or the body\n (`[\"SET\", \"foo\", \"bar\"]`), `/pipeline` and `/multi-exec`, `{result}` / `{error}`, `Upstash-Encoding: base64`, `Upstash-Response-Format: resp2`\n (RESP2 bytes, but at `/multi-exec`), and a\n database's Standard and Read Only tokens (the Read Only one refuses writes, SCAN and KEYS).\n- **Redis's semantics** are the kernel's (`@volter/world-core/redis`), for the commands Dub sends and the life sends\n (`src/semantics/shared.ts`, SERVED): SET, GET, GETDEL, DEL, EXISTS, EXPIRE, PEXPIRE, INCR, INCRBY, RENAME; HSET,\n HSETNX, HGET, HGETALL, HMGET, HDEL, HINCRBY; LPUSH, RPUSH, LPOP, LRANGE; SADD, SREM, SMEMBERS, SISMEMBER, SMISMEMBER;\n ZINCRBY, ZRANGE; XADD, XRANGE, XREVRANGE, XDEL; SCAN; EVAL and EVALSHA running the script's Lua (`@upstash/ratelimit`'s\n windows verbatim). Every other command is refused as Upstash refuses one it does not have, in a request or a script.\n- **QStash**:\n - Publishing: publish with method, timeout, delay, not-before, retries, deduplication (ten minutes), flow control's\n keyed rate, period and parallelism (a key alone keeps its limits), durations as `<number><unit>` or compound\n (`1d1h30m`), retry-delay expressions, comma-separated labels,\n callbacks and failure callbacks, each configured by its own `Upstash-Callback-*` / `Upstash-Failure-Callback-*`\n options; batch; enqueue into a queue, and a queue's upsert; the token as a bearer header or `qstash_token`.\n A destination that is not a URL is a URL Group the account does not hold (404).\n - Messages: a message's read with configured body/header redaction; cancellation by message ids, filters, or all pending messages in the account. Redaction preserves the original payload for delivery.\n - Delivery: each message is delivered when due, signed (`Upstash-Signature`, HS256 with the current key), and\n retried on QStash's backoff, each attempt waiting at most its timeout (the account's Pay as you go plan's two hours,\n which an `Upstash-Timeout` only shortens). Once out of retries, or answered 489 with `Upstash-NonRetryable-Error:\n true`, it goes to the DLQ and its failure callback is called. A queue delivers in order, as many at a time as its\n parallelism; the attempts due at one instant are sent at once, and a call holds its key's slot until its answer\n arrives.\n- **Workflow**: a run is started by its first invocation, and each later call carries the run's steps so far. It ends\n when `serve()` ends it or when it is cancelled; when a step is out of retries it fails.\n\n## Doors\n\n- `POST /_twin/users/{email} {password}` (console.upstash.com): a person who can sign in.\n- `POST /_twin/app-credentials {owner?}` (console.upstash.com): a World application's database and QStash credentials,\n as the runtime issues them (the descriptor's credential door).\n- `POST /_twin/destinations {url, status, headers?, body?, takes?, when?}` (QStash): how an application the World does\n not run answers at a URL, and after how long on the World's clock.\n- `GET /_twin/deliveries?to=<url>[&run=<id>][&message=<id>]` (QStash): every request QStash made there, with its\n answer's status once it arrived, or what was missed (`timeout`, `unreachable`).\n\n## Who it is for\n\nDub, as it ships (`journeys/demand.json`): its Redis caches, locks, streams and imports, its rate limits, its QStash jobs,\nqueues and Workflow runs, and the deliveries its routes verify. Rallly and Cal.com use Upstash Redis only when their\nvariables are set. The life (`journeys/customer-life.json`) is one studio's quarter on one account: Kiln on Redis,\nLooplinks on QStash and Workflow.\n\n## Not yet\n\n- The Developer API (`api.upstash.com/v2`): no application calls it; the console makes what they use.\n- QStash's schedules, URL groups, the DLQ's API, waiting for events, flow control's management API; a message\n read only while it is delivered or retried, as QStash keeps it.\n- Every Redis command no demand or life sends (Upstash's table holds 248).\n- Upstash Vector (Dub's docs embeddings): another product with its own wire.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "cloudflare",
|
|
7
|
+
"package": "@volter/twin-cloudflare",
|
|
8
|
+
"version": "3.0.11",
|
|
9
|
+
"integrity": "sha512-8JrSDMxmxzNy4Qkf4dLeaAU24tGDcW98vcjswh2XZLaGOjqWpxScT8IISWieaKz28wY4Om/xARADJZUrRlSdFg=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Cloudflare DNS, R2 and Worker deployment configuration. Worker programs are not executed; static asset behavior and API limits are documented in the README.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.68",
|
|
19
|
+
"@volter/world-ui": "*"
|
|
20
|
+
},
|
|
21
|
+
"repositoryDirectory": "cloudflare",
|
|
22
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
23
|
+
},
|
|
24
|
+
"readme": {
|
|
25
|
+
"path": "package/README.md",
|
|
26
|
+
"markdown": "# @volter/twin-cloudflare\n\nFor Open Autonomy, RH2, the platform callers and the shipped storage, custom-domain and CAPTCHA features of Dub, Twenty, Cal.com, Rallly and LibreChat. Postiz’s alternative storage driver and Twenty’s optional CAPTCHA driver are recorded in `journeys/demand.json` and exercised by the customer life. A local Cloudflare: the API v4 that the unmodified `cloudflare` SDK and wrangler call (`api.cloudflare.com/client/v4`,\nthe `api/` lane), and R2 over its S3 API (`<account>.r2.cloudflarestorage.com`, the `r2/` lane). It also covers the\ndashboard's sign-in and its API Tokens pages (My Profile's and R2's, `dash.cloudflare.com`), and Turnstile's `api.js`,\nits challenge frame and siteverify (`challenges.cloudflare.com`), all over one vendor state.\n\n## Use with an existing app\n\nIn an app that already uses this vendor, install this exact release and the product CLI:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.68 @volter/twin-cloudflare@3.0.11\nnpx volter world init --name my-app --twins cloudflare --source cloudflare=@volter/twin-cloudflare\n```\n\nReview the detected vendor and generated bindings before booting. Read the credential names and limitations below; the World supplies throwaway credentials. Then run your app's own command through the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nHere `npm test` is your app's existing command; replace it with your app or test command. `down` retains state.\nA later `up` resumes it; do not reset or initialize again merely to return.\n\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\n\nA Protocol 3 pack of lanes ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md)). Each lane's surface is generated from its own spec (`api/spec`: Cloudflare's OpenAPI document; `r2/spec`:\nS3's model with R2's differences). Its handlers are in `<lane>/src/semantics/<family>.ts`, its state machines in\n`<lane>/src/semantics/states.ts`, and operations outside scope answer the lane's gap (API \"No route for the URI\", R2 NotImplemented).\n\n```bash\nworld-cloudflare serve [--port N] [--root DIR] [--read-only]\n```\n\n## The World's Cloudflare\n\nThe application's account comes from the World's credential door (`/_twin/app-credentials`). A zone is added through\nthe API (`POST /zones`) and turns active when the registrar's nameservers are published (the `dns` door).\n\n- **API tokens**: one model for both lanes. A token is a set of policies, each allowing permission groups\n (`Workers Scripts Write`, `DNS Write`, `Workers R2 Storage Bucket Item Read`, …) over an account, a zone (or every\n zone of an account), R2 buckets or the person.\n- **Where tokens are made**: on R2's API Tokens page, or on My Profile's API Tokens page from a template URL\n (`permissionGroupKeys`), as Open Autonomy's setup links it.\n- **Checking**: a token is kept by its SHA-256. The API refuses an operation whose permission group the token lacks on\n the account or zone it names (403, code 10000), and a disabled or expired token (401).\n- **R2 credentials**: R2's S3 credentials are the token's id and the SHA-256 of its value.\n\n## What it models\n\n- **Workers**: a module upload with its assets (multipart, deployed at once) and its Durable Object migrations (classes\n made, renamed and deleted), the service read, the workers.dev subdomain and a script's route on it, its settings read,\n Cron Trigger schedules installed and read back, secrets put (their text never answered, kept across uploads), the deployments and versions lists, a version's detail\n and the account's scripts, as wrangler deploys and the platform's deploy rehearsal reads back.\n- **R2**: buckets through the API and the S3 API (with a location hint, or made by an upload's\n `cf-create-bucket-if-missing`); objects (their checksums checked), presigned URLs, CORS and lifecycle configurations\n (R2's default rule aborting an upload after seven days), listings by delimiter and continuation token, multipart\n uploads (large-part completion, composite/full-object checksums and SSE-C key-gated objects), custom domains attached and listed through the API, and public reads at them.\n- **Workers static assets and Custom Domains**: the files `wrangler deploy` uploads through an assets upload session\n (each kept with the content type it was uploaded with), a version's assets served once a deployment sends it the\n traffic (a new version upload and a deployment are wrangler's path for a Worker it has deployed before), the config's\n `html_handling`, `not_found_handling`, `_redirects` and `_headers` (parsed as the API parses them), and a hostname in\n one of the account's active zones attached as the Worker's Custom Domain (the Domains API, or wrangler's changeset and\n domain records); a hostname the zone holds DNS records at is refused, as Cloudflare refuses it. Inside the World the\n hostname answers as Cloudflare's asset worker does (`src/semantics/shared.ts`, ported from Cloudflare's\n `workers-shared`).\n- **Zones**: a zone's DNS records listed, made and deleted, with vendor timestamps and type-dependent proxy capability; the internal zone parent never appears in the record reply; Cloudflare for SaaS custom hostnames (listed, made, edited, deleted). A\n hostname's ownership and certificate validation records are computed for the method chosen, and it turns active\n when its customer publishes them.\n- **Turnstile**: widgets made through the API (sitekey and secret), the `api.js` widget and its challenge, a visitor's token checked once at siteverify\n within 300 seconds (`timeout-or-duplicate` after).\n- **Tokens**: verification (`/user/tokens/verify`), an account's tokens listed, and a token rolled or revoked on the\n dashboard's token pages.\n- **A vendor-backed World**: every stored resource is read back (the account, zones and custom hostnames, the account's\n tokens, each zone's DNS records retaining their vendor IDs, Workers with each version's detail, deployments and secrets, Durable Object namespaces, the workers.dev\n subdomain, Turnstile widgets from their secret-free listings, Notifications destinations and policies, buckets per\n jurisdiction and their custom domains, objects with their bytes and headers, in-progress uploads and their parts);\n the API's calls are sent with the root's token, R2's to the account's own host signed with SigV4 under the root's R2\n keys (the descriptor's `lanes` strategy). A widget's live secret is not read back; its synthetic secret remains available through the detail API. A person and their memberships are not read back: the root's account token\n acts as no user. A deploy sends the World's account as the one the root's token reaches (`account`), and a script or\n version upload with static assets runs Cloudflare's upload protocol again (`performs`, `uploadWithAssets`: the session\n opened with the manifest the World's session held, the files from the World's blobs with the JWT Cloudflare issues,\n then the upload with its completion token).\n- **Notifications**: webhook destinations and policies made and listed; the SSL for SaaS Custom Hostnames alert\n (validation, issuance, deployment, deletion) sent to a policy's webhooks with `cf-webhook-auth`, the destination's\n secret, as Twenty's guard reads it.\n\n## Doors\n\n- `POST /_twin/users/{email} {password}` (dash.cloudflare.com): a person who can sign in.\n- `POST /_twin/app-credentials`: the application's account and token.\n- `POST /_twin/dns {name, type, value}`: a record published at a DNS host outside Cloudflare (a SaaS customer's own\n domain, or a registrar's nameservers for a zone), which Cloudflare's checks then see.\n- `GET /_twin/deliveries?to=&type=`: every notification sent, as the receiving server got it.\n- `GET /_twin/hosts`: the hostnames the World routes here: custom domains connected to R2 buckets, Workers Custom\n Domains and enabled `workers.dev` deployment URLs.\n\n## Not yet\n\n- A Worker's requests: the World's Workers are uploaded and deployed, never run; at a Custom Domain or `workers.dev` URL only the Worker's\n static assets answer (a request its script would take is refused with 501).\n- A vendor-backed refresh reads a bucket, not its CORS or lifecycle configuration, and a part, not its bytes (no S3\n operation answers a part's bytes): an observed part completes nothing until it is uploaded again.\n"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "resend",
|
|
7
|
+
"package": "@volter/twin-resend",
|
|
8
|
+
"version": "1.0.1",
|
|
9
|
+
"integrity": "sha512-rorxvx2YrMhmwB+bouDvfqY1ykbkWE4BDgjWFD6ZAFLmEwCsxxbcRy+lqGWo3hwQaCRMxdxP+KHn6bnIMlowcA=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Resend transactional email, delivery events, domains and inbox inspection. Delivery is simulated; no real email is sent.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.64"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "resend",
|
|
21
|
+
"bugs": "https://github.com/volter-ai/twin-packs-open/issues"
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-resend\n\nA local Resend. Its API (`api.resend.com`) serves the calls Dub, Twenty, Postiz and Volter World's platform make: emails\nsent singly and in batches and listed, sending domains (created, read, listed, updated, verified, removed), and received\nemails and their list. Resend's webhooks go to a team's\nendpoints, signed as svix signs them. The inbound CDN (`inbound-cdn.resend.com`) serves a received email's raw message.\n\n## Use with an existing app\n\nIn an app that already uses this vendor, install this exact release and the product CLI:\n\n```console\nnpm install --save-dev --save-exact @volter/world@3.0.67 @volter/twin-resend@1.0.1\nnpx volter world init --name my-app --twins resend --source resend=@volter/twin-resend\n```\n\nReview the detected vendor and generated bindings before booting. Read the credential names and limitations below; the World supplies throwaway credentials. Then run your app's own command through the World:\n\n```console\nnpx volter world up\nnpx volter world run -- npm test\nnpx volter world log\nnpx volter world down\n```\n\nHere `npm test` is your app's existing command; replace it with your app or test command. `down` retains state.\nA later `up` resumes it; do not reset or initialize again merely to return.\n\nPublisher and catalog contribution instructions: [the public publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md).\n\n\nA Protocol 3 pack ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md)). Its surface is generated\nfrom Resend's OpenAPI document (`spec/`). Handlers\nare in `src/semantics/<family>.ts`, the key front in `src/semantics/around.ts`, the lifecycle in\n`src/semantics/clock.ts`, and state machines in `src/semantics/states.ts`.\n\n```bash\nworld-resend serve [--port N] [--root DIR] [--read-only]\n```\n\n## What it models\n\n- **Keys**:\n - A key is made on the API Keys page (a door) and held by its SHA-256.\n - A request with none is `401 missing_api_key`, an unknown one `400`, and a deleted one `403 restricted_api_key`.\n - Everything a key does is its team's.\n- **Sending**:\n - `from`, `to` (at most 50), `subject` and a body are required.\n - The sender must be at a verified domain of the team, or at `resend.dev` sending only to the team owner's address.\n - A batch of up to 100 is checked whole before any is sent.\n - Attachment bytes are held in blobs and retained for inbox observation. Dub's ISO scheduled sends wait until their requested time before following the ordinary delivery lifecycle.\n- **An email's life**: `queued`, then `sent` at once. Five seconds later it is `delivered`, or `bounced` when a\n recipient's server refuses its domain's mail (a door). A recipient may then open it (on a domain with open tracking)\n or mark it as spam (doors).\n- **Domains**:\n - Each has its DKIM, SPF MX and TXT, Tracking and Receiving records.\n - Verifying makes it pending. It is verified ten minutes after the later of the verify and its last record at the\n owner's DNS host (a door), or failed after 72 hours without them.\n - Updated: open and click tracking, TLS, the tracking subdomain and capabilities.\n- **Receiving**: mail to a verified receiving domain (a door) is a received email, with attachment metadata and bytes retained, read with its pre-signed raw\n download URL, which lasts an hour.\n- **Webhooks**:\n - Sent for `email.sent`, `email.delivered`, `email.bounced`, `email.opened`, `email.complained` and `email.received`.\n - Each goes to the team's endpoints that subscribe to it, signed with `svix-id`, `svix-timestamp` and\n `svix-signature`.\n\n## Doors\n\n- `POST /_twin/api-keys {name, team, owner}` and `DELETE /_twin/api-keys/{id}`: the API Keys page.\n- `POST /_twin/webhooks {team, endpoint, events}`: the Webhooks page; answers the signing secret.\n- `POST /_twin/dns {name, type, value}`: a record at the owner's DNS host. Supply its fully qualified name: for a domain `example.com`, returned `send` means `send.example.com` and `resend._domainkey` means `resend._domainkey.example.com`; use the returned value unchanged.\n- `POST /_twin/recipients/{domain} {rejects}`: an outside server that refuses mail.\n- `POST /_twin/mail/{email_id}/open` and `/complain` `{to}`: a recipient's act.\n- `POST /_twin/inbound {from, to, subject, text?, html?, inReplyTo?, headers?, received_for?, authentication?, attachments?}`: mail from outside to a receiving domain.\n- `GET /_twin/mail?to=`: an inbox.\n- `GET /_twin/deliveries?to=[&type=][&email=]`: the webhooks sent.\n\n## Not yet\n\nBroadcasts, segments, topics, templates, suppressions, audiences and contacts, the API\nKeys and Webhooks APIs and contact properties: no application here calls them.\n\n## Vendor-backed\n\nLists are newest first, paged by `limit`, `after` and `before`. A refresh reads sent emails, received emails and domains back from their\nlists and detail operations; Resend's signed email events are ingested (each folded into its email by `email_id`, its type the email's\n`last_event`); calls are charged within a fixed allowance of 120 per minute, below the documented 600 per minute.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "linear",
|
|
7
|
+
"package": "@volter/twin-linear",
|
|
8
|
+
"version": "3.0.4",
|
|
9
|
+
"integrity": "sha512-OHqIROUZYb5mlceMPRrjDNpycvRahII+2xh/B461bUREXFY7pKszUy3AwlQmAG+0bdYb3qFWf5JmRYhJn1uavw=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Protocol 3 Linear twin for the official SDK viewer, team and issue workflow and the documented issue-filing integration.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.105"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "linear",
|
|
21
|
+
"bugs": null
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-linear\n\nA Protocol 3 Linear twin for a workspace’s issue-filing integration and the Linear SDK\ninstalled by Twin ([demand](./journeys/demand.json)). It serves Linear’s GraphQL endpoint,\nOAuth authorization-code installation, token refresh and configured client-credentials grants,\nworkspace/team/project discovery,\nworkflow states, issue creation/update/archive, labels and comments. The customer life and\npublished-example journey define the modeled scope ([decisions](./journeys/decisions.json)).\n\nResources are read back with declared GraphQL refresh queries, including archived issues.\nMutation deployment uses the vendored schema to adopt the resource returned by Linear.\nRefresh-token retries preserve the returned pair during Linear’s documented 30-minute grace.\nThe executor budget stays below the documented API-key request quota.\n\nThe World’s doors represent settings/UI actions Linear’s API does not expose:\n`POST /_twin/workspaces`, `POST /_twin/workspaces/{urlKey}/people`,\n`POST /_twin/app-credentials` and `POST /_twin/api-keys`. The local credential door\n`POST /_twin/local-credentials` uses those same settings actions to make an idempotent synthetic\nstarter workspace/owner, issue its personal key and register a World OAuth client. It supplies\n`LINEAR_API_KEY`, `LINEAR_CLIENT_ID` and `LINEAR_CLIENT_SECRET`; the personal key names a stored\nowner and is retained across stop/resume. Teams and projects are created through the\nvendor API. The authorize screen uses the registered callback and carries its state back.\n\nThe published relation, logical, date, label, comment, estimate and project-lead filters are served.\nOther GraphQL fields, private-team access management, webhook configuration, PKCE and OAuth\nrevocation are outside this modeled scope and are refused. The SDK’s default\nviewer, team and issue selections are modeled for the official SDK 86.0.0's create/update/read flow\nin [the installed customer entry](./journeys/first-use.json). This does not claim every SDK method.\nNo webhook subscription is made by this life;\nthere is no invented webhook delivery. Release assessments are retained by\n[the independent catalog](https://github.com/volter-ai/twin-catalog-open).\n\nInstall the selected release in your app with `npm install --save-dev @volter/twin-linear@3.0.3`.\nThe app keeps its real `@linear/sdk`; the packaged customer entry pins 86.0.0.\nFor local setup, use the app folder’s `volter world init`, review the detected vendors,\nand keep Linear when the app needs it. Start with `volter world up`, run the app or seed\nthrough `volter world run -- <command>`, and stop with `volter world down`. The World’s\n`GET /twin` describes identity, time, and the available doors.\n\nThe workspace door takes `{ \"name\": \"Example\", \"urlKey\": \"example\", \"owner\": { \"name\": \"Ada\", \"email\": \"ada@example.invalid\", \"password\": \"example-password\" } }`.\nThe people door takes `{ \"name\", \"email\", \"password\" }`; the key door takes `{ \"email\", \"label\" }`.\nThe app door takes `{ \"name\", \"redirect_uris\": [\"https://app.example/callback\"] }`;\nits optional `client_credentials: { workspace: \"example\", teamIds: [...] }` represents\nthe settings toggle and the app user’s configured team access. All credentials are synthetic.\n\nProfiles, public-team settings, empty optional-feature state, issue relations and counts are stored\nin their vendor response shapes and preserved by the declared refresh queries. `isMe` is resolved\nfor the current caller. Creator counts include archived issues; team counts exclude them unless\n`includeArchived: true` is requested. The kernel maintains these counters on recorded writes.\nThe starter leaves cycles, triage, integrations, sharing and automation unconfigured. Its inactive\nnumeric settings, avatar colors, invitation hashes, app actor email addresses and branch naming are\nexplicitly synthetic choices where upstream documentation does not declare production defaults.\nMutations for those additional features remain outside scope; absent feature state does not claim\nthat their behavior is implemented.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"release": {
|
|
4
|
+
"schemaVersion": 1,
|
|
5
|
+
"source": "twin-packs-open",
|
|
6
|
+
"vendor": "clerk",
|
|
7
|
+
"package": "@volter/twin-clerk",
|
|
8
|
+
"version": "1.0.2",
|
|
9
|
+
"integrity": "sha512-3HZEt5czGpF/wEWcoDk+1/2Ln6J4Tg00kqFbgWTJ6VP8th5myZ1c9x2QowBmFcSdmdp0U00HMMxD7VJ4ucSkxw=="
|
|
10
|
+
},
|
|
11
|
+
"packageMetadata": {
|
|
12
|
+
"description": "Local Clerk twin — a faithful, stateful local Clerk Backend API your real `@clerk/backend` SDK talks to unmodified. Users, sessions, orgs, real signed JWTs + a JWKS endpoint. Mirror, simulate, and fork. Built on @volter/world-core.",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22.3"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@volter/world-core": "^3.0.96"
|
|
19
|
+
},
|
|
20
|
+
"repositoryDirectory": "clerk",
|
|
21
|
+
"bugs": null
|
|
22
|
+
},
|
|
23
|
+
"readme": {
|
|
24
|
+
"path": "package/README.md",
|
|
25
|
+
"markdown": "# @volter/twin-clerk\n\nA local Clerk instance: the **Backend API** an application's server calls (`@clerk/backend`, unmodified, at\n`https://api.clerk.com/v1`) and the **Frontend API** the unmodified `@clerk/clerk-js` bundle calls from the browser (the\ninstance's own host, `twin.clerk.accounts.dev`), over one state. A user made through the Backend API signs in through\nclerk-js; a session clerk-js starts is one the Backend API lists and mints tokens for.\n\nThe Frontend API also answers at `frontend-api.clerk.dev`, the destination of Clerk’s documented same-site proxy and vgauth’s Worker. That host routes directly to the Frontend API lane, with the same instance state and browser credentials.\n\nA Protocol 3 derived pack ([publisher guide](https://github.com/volter-ai/twin-catalog-open/blob/main/docs/contributing.md), \"Protocol 3\" and \"Creating a\npack\"): the surface is generated from Clerk's published OpenAPI documents (`spec/`, `fapi/spec/`), plain reads, writes\nand deletes are the derived core's, the state machines are `src/semantics/states.ts`, and handlers by operationId\n(`src/semantics/<family>.ts`) serve only what an operation does beyond them. Every other operation answers Clerk's own\n404. The immutable catalog assessment records the declared surface, measured journeys and remaining gaps.\n\n```bash\nworld-clerk serve [--port N] [--root DIR] [--read-only]\n```\n\nA World makes its people through the Backend API's own `POST /users`. Nothing is signed in.\n\n## What it models\n\n- **Backend API**: users (made, updated, their metadata merged or replaced, listed and counted with Clerk's filters,\n deleted), sessions (made for a test, listed, revoked, their tokens), sign-in tokens (made,\n revoked, used once by the Frontend API), an instance's organization settings (Organizations are off until\n turned on, as on a new Clerk instance), custom permissions and roles beside the system ones, organizations with\n their memberships and invitations, JWT templates, SAML enterprise configuration and the instance's public keys.\n- **Frontend API** (what clerk-js needs to boot and what the applications measured drive through it): the environment,\n the dev browser, the client and its `__client` cookie, sign-up by email and password (the address verified by an\n emailed code) and by an invitation's ticket, sign-in by password, by an emailed code and by ticket, sessions (touched,\n read and their tokens), an\n invitation's link, and `/.well-known/jwks.json`. Clerk's published clerk-js bundle (5.127.2,\n `vendor/clerk-js/`, with its SOURCE.md) is served as published at the `/npm/@clerk/clerk-js` loader path.\n- **Webhooks**: user.deleted, Svix-signed, to the instance's webhook endpoints. The payload includes timestamp, instance_id, request event_attributes and the deleted user's external_id. Each delivery is recorded; the Dashboard endpoint is set through `POST /_twin/webhook-endpoints`.\n\nThe OAuth identity-provider flow serves the account worker used by Volter Editor: authorization redirects to sign-in and explicit consent, then a registered callback receives a single-use code bound to S256 PKCE. The worker exchanges it at `/oauth/token`; refresh grants retain the user and selected organization. Access tokens use the `at+jwt` header type Clerk's SDK expects; OpenID Connect ID tokens use `JWT`. Register the public OAuth application with `POST /v1/oauth_applications` before using it. Codes expire after ten minutes, access and ID tokens after one day, and refresh tokens after ten years in the pinned Frontend API spec.\n\nThe Frontend API accepts the documented `clerk.<application domain>` host family and `frontend-api.clerk.dev`; proxy calls require a held instance secret key in `Clerk-Secret-Key`, the full `Clerk-Proxy-Url`, and `X-Forwarded-For`.\n\nOrganization settings are stored as the Backend API's `OrganizationSettings` singleton and read back through `GET /v1/instance/organization_settings`; the Frontend environment renders its domain fields in the Frontend shape. Dashboard-only sign-in configuration remains private bookkeeping. Memberships retain the Backend API's `public_user_data.user_id` reference, including after refresh. The known-resource scopes read JWT templates, enterprise connections and their SAML children without promising enumeration for those types.\n\n## Keys\n\nThe Backend API takes only the keys the instance holds: the application's, which the World issues when it boots\n(`POST /_twin/app-credentials`, the descriptor's credential door, with the publishable key, the `CLERK_JWT_KEY` a\nbackend verifies session tokens with and the webhook signing secret), and every key the API Keys page's door made. No\n`Authorization` header is Clerk's 401 `authorization_header_format_invalid`, and any other key, whatever its shape, is\nits 401 `clerk_key_invalid`. A request with no secret key is never the Backend API's: on a Frontend API path it is the\nbrowser's, answered by the Frontend API.\n\n**Each World signs with its own key.** Session tokens, the tokens of JWT templates without a key of their own, and\ninvitation tickets are signed with an RSA key the World makes once at random (`ctx.signingKey`), served as the\ninstance's JWKS, so a token verifies only against the World that issued it and no one can mint one from this package.\nA template with its own signing key signs with that key, in its algorithm (RSA or HMAC, SHA-256 to 512; others are\nrefused).\n\n## Doors\n\nThe World's hands on the instance, standing in for the Clerk Dashboard (`src/semantics/doors.ts`); the `POST` doors are\nrefused on a read-only twin:\n\n- `POST /_twin/secret-keys {name}`: a secret key, as the API Keys page shows it once (`sk_test_…` on a development\n instance); the twin keeps its hash.\n- `POST /_twin/webhook-endpoints {url, events, signing_secret?}`: a webhook endpoint and its `whsec_…` signing secret\n (the one given, when the World's application already holds one).\n- `POST /_twin/instance {…}`: the instance's sign-up settings (password on or off, legal consent, organization\n membership optional or required, the Frontend API host, the Native API on or off).\n- `POST /_twin/native-applications {platform, …}`: an iOS app (`app_id_prefix`, `bundle_id`) or Android app\n (`package_name`) registered on the Native applications page. A native client's request (`_is_native=true`, its client\n token in `Authorization`) is Clerk's 400 `native_api_disabled` until the Native API is on.\n- `GET /_twin/emails?to=<address>`: what Clerk sent an address (verification codes, invitations), oldest first.\n- `GET /_twin/webhook-messages?type=<event>`: what was delivered to the webhook endpoints, oldest first.\n\n## Not modelled\n\nOAuth device authorization, token exchange, dynamic registration, userinfo and revocation; SSO sign-in (an enterprise connection is configured, never signed in through) and passkeys; multi-factor authentication; phone numbers; application-invitation acceptance and revocation,\nallowlist and blocklist, actor tokens, redirect URLs, domains, OAuth application updates and deletion, and the webhook\nendpoints API; uploaded logos and profile images; standalone SAML mutations and enumeration (known connections are readable), permission/role deletion, UserProfile and client session removal, and every Frontend API route clerk-js's organization components drive. Each\nanswers the gap, never a fabricated success.\n\nThe first-party account broker’s production share invitation calls Backend API `CreateInvitation`; the companion stores that application invitation, sends its ticket to the modeled recipient inbox, and exposes `ListInvitations` for read-back. These operations honor notification, metadata, expiration and duplicate handling. Application-invitation acceptance, revocation and bulk creation remain separate gaps.\n"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/docs/operations.md
CHANGED
|
@@ -61,6 +61,17 @@ Untrusted-account submissions need genuine current-head non-author human moderat
|
|
|
61
61
|
|
|
62
62
|
## Recover index publication
|
|
63
63
|
|
|
64
|
+
To retain workflow documentation for recorded releases, run the data-only capture in a catalog checkout:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
node bin/twin-catalog.mjs capture-content
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
It reads immutable tarballs at their recorded integrity and writes `content/<release-id>.json`.
|
|
71
|
+
Existing receipts are reused. Commit them through the maintainer maintenance path before publishing;
|
|
72
|
+
this neither assesses a candidate nor changes an admission record. The publisher includes the receipts
|
|
73
|
+
in the index and binds their hashes to its snapshot. A missing README remains missing.
|
|
74
|
+
|
|
64
75
|
Retry current protected main after resolving the recorded cause:
|
|
65
76
|
|
|
66
77
|
```sh
|
|
@@ -69,6 +80,14 @@ gh workflow run publish.yml --repo "$catalog_repository" --ref main
|
|
|
69
80
|
|
|
70
81
|
The workflow verifies admission and protection, then reuses a published version only when source and digest match. It cannot overwrite a conflicting identity. Retain the new receipt and compare registry integrity before calling the upload confirmed. No platform build, candidate test or hosted deployment is part of this job.
|
|
71
82
|
|
|
83
|
+
The product site is an independent consumer. Its configured operator scheduler runs the site-only
|
|
84
|
+
`apps/www/scripts/refresh.py` command documented in the World website's publishing instructions.
|
|
85
|
+
It installs an exact released index in a disposable directory, retains registry integrity, builds
|
|
86
|
+
and uploads the product site, and confirms the production snapshot. A site refresh does not
|
|
87
|
+
rebuild or release the platform, change an admission, or replace a user's World pin. Hosting
|
|
88
|
+
custody stays with that site operator; this catalog receives no hosting credential. Inspect the
|
|
89
|
+
site publisher's retained receipt and failure logs when the npm snapshot is newer than the site.
|
|
90
|
+
|
|
72
91
|
## Recommend, reject or revoke
|
|
73
92
|
|
|
74
93
|
A moderator rejects a PR with a concrete reason. An unmerged readiness success adds no release to the index.
|
package/docs/process.md
CHANGED
|
@@ -52,6 +52,16 @@ The JSON-only reader also projects installed customer scope, pinned SDK dependen
|
|
|
52
52
|
Historical assessments without these retained fields show them as unavailable; current registry metadata does not
|
|
53
53
|
fill missing historical evidence. A provenance link establishes source and build identity, not vendor fidelity.
|
|
54
54
|
|
|
55
|
+
Maintainers can retain release documentation with `twin-catalog capture-content`. This reads each recorded
|
|
56
|
+
package/version's tarball from the policy registry, verifies its recorded SHA-512 integrity, and captures its
|
|
57
|
+
manifest listing facts and README as data in `content/`. It never installs, imports or executes a pack. The
|
|
58
|
+
published snapshot binds those receipts by SHA-256; its reader checks both the receipt and release identity.
|
|
59
|
+
Consumers can display that version's README without fetching a publisher's current branch. Missing README
|
|
60
|
+
content stays unavailable. Artifact facts can supply older listings, but never supply missing assessment,
|
|
61
|
+
customer, browser or provenance evidence. Capture is an explicit maintenance action, not a test trigger.
|
|
62
|
+
New assessments retain the same README from the already unpacked artifact during preparation; the reader can
|
|
63
|
+
use that existing checksum-bound report directly. No additional assessment or documentation workflow runs.
|
|
64
|
+
|
|
55
65
|
Publishers describe useful workflows, setup and throwaway credential requirements, companion services, supported
|
|
56
66
|
SDK/API versions and explicit limitations in the package README. Model replies, simulated email/search and partial
|
|
57
67
|
interfaces are labeled. Declared gaps remain in the coverage denominator. No publisher badge or aggregate grade
|
|
@@ -220,9 +230,9 @@ historical records. Consumers read `recommendations.json` and `revocations.json`
|
|
|
220
230
|
release is different from offering it as an install default: pending, rejected, revoked and prerelease versions are
|
|
221
231
|
never automatic selections. A missing or failing assessment is never inferred from a publisher badge.
|
|
222
232
|
|
|
223
|
-
|
|
224
|
-
the immutable version and admission PR/evidence. It
|
|
225
|
-
results
|
|
233
|
+
The public catalog groups implementations under a vendor, attributes the repository and publisher, and links to
|
|
234
|
+
the immutable version and admission PR/evidence. It displays release documentation and Setup separately from
|
|
235
|
+
support counts, installed-customer journeys and replay results. A contributor sees the PR check, one updated feedback comment, and downloadable workflow artifacts.
|
|
226
236
|
Readiness checks bind the report digest, workflow run ID and attempt in their external receipt. GitHub may replace
|
|
227
237
|
the display URL and attach a manually dispatched check to an older PR check suite; that display association is not
|
|
228
238
|
the report's source. After authorized merge, publication fetches the exact recorded workflow attempt and requires
|
package/lib/browse.d.mts
CHANGED
|
@@ -69,7 +69,7 @@ export type Release = {
|
|
|
69
69
|
export type CatalogRelease = Release & {
|
|
70
70
|
packageMetadata: null | {
|
|
71
71
|
description: string | null;
|
|
72
|
-
license: string;
|
|
72
|
+
license: string | null;
|
|
73
73
|
engines: Record<string, string>;
|
|
74
74
|
peerDependencies: Record<string, string>;
|
|
75
75
|
repositoryDirectory: string | null;
|
|
@@ -80,6 +80,8 @@ export type CatalogRelease = Release & {
|
|
|
80
80
|
packageUrl: string;
|
|
81
81
|
issuesUrl: string | null;
|
|
82
82
|
};
|
|
83
|
+
documentation: null | { markdown: string | null; path: string | null; receiptPath: string;
|
|
84
|
+
receiptSha256: string; artifactIntegrity: string };
|
|
83
85
|
revoked: { reason: string } | null;
|
|
84
86
|
selectable: boolean;
|
|
85
87
|
default: boolean;
|
package/lib/browse.mjs
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { digest, loadIndex, read, requireThat, selection, stable, submissionId, validateIndex } from './model.mjs';
|
|
5
|
+
import { contentIdentity, contentReceipt } from './content.mjs';
|
|
5
6
|
|
|
6
7
|
const textOrder = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
7
8
|
const releaseKey = (v) => `${v.package}@${v.version}`;
|
|
8
9
|
|
|
9
|
-
function packageDetails(bound, source, packageName, version) {
|
|
10
|
-
const metadata = bound?.report.prepared?.packageMetadata;
|
|
10
|
+
function packageDetails(bound, source, packageName, version, content) {
|
|
11
|
+
const metadata = content?.packageMetadata ?? bound?.report.prepared?.packageMetadata;
|
|
11
12
|
if (!metadata) return null;
|
|
12
|
-
const commit = bound
|
|
13
|
+
const commit = bound?.report.prepared?.provenance?.sourceCommit;
|
|
13
14
|
const directory = metadata.repositoryDirectory ?? '';
|
|
14
15
|
const parts = typeof directory === 'string' ? directory.split('/').filter(Boolean) : null;
|
|
15
16
|
const validDirectory = parts && parts.every((part) => part !== '.' && part !== '..' && !part.includes('\\'));
|
|
@@ -85,7 +86,8 @@ export function browse(root, { vendor, package: packageName, integrity = null }
|
|
|
85
86
|
requireThat(expected.length === records.size && expected.every((v) => stable(v) === stable(records.get(releaseKey(v)))),
|
|
86
87
|
'catalog records differ from index data');
|
|
87
88
|
const snapshotDigest = (vendors) => digest({ evidence: references, sources: index.sources, vendors,
|
|
88
|
-
recommendations: index.recommendations, revocations: index.revocations
|
|
89
|
+
recommendations: index.recommendations, revocations: index.revocations,
|
|
90
|
+
...(catalog.content ? { content: catalog.content } : {}) });
|
|
89
91
|
// Publication can append newly admitted vendors after the legacy vendors. Directory enumeration is alphabetical;
|
|
90
92
|
// catalog.json retains the publication order. Accept either only when its complete digest matches the snapshot.
|
|
91
93
|
const publicationOrder = new Map([...new Set(catalog.versions.map((v) => v.vendor))].map((name, at) => [name, at]));
|
|
@@ -115,10 +117,19 @@ export function browse(root, { vendor, package: packageName, integrity = null }
|
|
|
115
117
|
versions: p.versions.map((v) => {
|
|
116
118
|
const record = records.get(`${p.name}@${v.version}`);
|
|
117
119
|
const bound = reportFor(root, record);
|
|
120
|
+
const contentReference = catalog.content?.[submissionId(contentIdentity(record))];
|
|
121
|
+
const content = contentReceipt(root, record, contentReference);
|
|
122
|
+
const preparedReadme = bound?.report.prepared?.readme;
|
|
123
|
+
const documentation = content ? { markdown: content.readme?.markdown ?? null,
|
|
124
|
+
path: content.readme?.path ?? null, receiptPath: contentReference.path,
|
|
125
|
+
receiptSha256: contentReference.sha256, artifactIntegrity: v.integrity } :
|
|
126
|
+
preparedReadme ? { ...preparedReadme, receiptPath: record.evidence.reportPath,
|
|
127
|
+
receiptSha256: record.evidence.reportSha256, artifactIntegrity: v.integrity } : null;
|
|
118
128
|
const revoked = index.revocations.find((r) => r.package === p.name && r.version === v.version);
|
|
119
129
|
const selectable = v.status === 'live' && !v.version.includes('-') && !revoked;
|
|
120
130
|
const quick = bound?.report.quick, browser = bound?.report.browser;
|
|
121
|
-
return { ...v, packageMetadata: packageDetails(bound, source, p.name, v.version),
|
|
131
|
+
return { ...v, packageMetadata: packageDetails(bound, source, p.name, v.version, content),
|
|
132
|
+
documentation,
|
|
122
133
|
revoked: revoked ? { reason: revoked.reason } : null, selectable: Boolean(selectable),
|
|
123
134
|
default: choice?.p.name === p.name && choice.v.version === v.version,
|
|
124
135
|
assessment: { recorded: record.assessed, available: Boolean(bound), evidence: record.evidence,
|
package/lib/content.mjs
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Artifact documentation is data, independent of assessment and admission evidence.
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { digest, read, requireThat, stable, submissionId, validateSubmission, write } from './model.mjs';
|
|
6
|
+
import { artifactBytes, metadata } from './registry.mjs';
|
|
7
|
+
|
|
8
|
+
export const contentIdentity = (v) => ({ schemaVersion: 1, source: v.source, vendor: v.vendor,
|
|
9
|
+
package: v.package, version: v.version, integrity: v.integrity });
|
|
10
|
+
export function contentReceipt(root, v, reference) {
|
|
11
|
+
if (!reference) return null;
|
|
12
|
+
const identity = contentIdentity(v), path = `content/${submissionId(identity)}.json`;
|
|
13
|
+
requireThat(reference.path === path && /^[a-f0-9]{64}$/.test(reference.sha256), 'invalid release content reference');
|
|
14
|
+
const receipt = read(join(root, path));
|
|
15
|
+
requireThat(digest(receipt) === reference.sha256, `${v.package}@${v.version}: content checksum differs`);
|
|
16
|
+
requireThat(receipt.schemaVersion === 1 && stable(receipt.release) === stable(identity), 'release content identity differs');
|
|
17
|
+
requireThat(receipt.packageMetadata && (receipt.readme === null ||
|
|
18
|
+
(typeof receipt.readme?.markdown === 'string' && /^package\/readme(?:\.md|\.markdown|\.txt)?$/i.test(receipt.readme.path))),
|
|
19
|
+
'invalid retained release documentation');
|
|
20
|
+
return receipt;
|
|
21
|
+
}
|
|
22
|
+
export function retainedContent(root, index) {
|
|
23
|
+
const references = {};
|
|
24
|
+
for (const e of index.vendors) for (const p of e.packages) for (const v of p.versions) {
|
|
25
|
+
if (!v.integrity) continue;
|
|
26
|
+
const release = contentIdentity({ vendor: e.vendor, package: p.name, source: p.source, ...v });
|
|
27
|
+
const id = submissionId(release), path = `content/${id}.json`;
|
|
28
|
+
if (!existsSync(join(root, path))) continue;
|
|
29
|
+
const reference = { path, sha256: digest(read(join(root, path))) };
|
|
30
|
+
contentReceipt(root, release, reference);
|
|
31
|
+
references[id] = reference;
|
|
32
|
+
}
|
|
33
|
+
return references;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Read named members to stdout only: no extraction, installation or package execution.
|
|
37
|
+
function archive(bytes, args) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const child = spawn('tar', args, { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
40
|
+
const out = [], errors = [];
|
|
41
|
+
child.stdout.on('data', chunk => out.push(chunk));
|
|
42
|
+
child.stderr.on('data', chunk => errors.push(chunk));
|
|
43
|
+
child.on('error', reject);
|
|
44
|
+
child.stdin.on('error', reject);
|
|
45
|
+
child.on('close', code => code === 0 ? resolve(Buffer.concat(out).toString('utf8')) :
|
|
46
|
+
reject(new Error(`read artifact archive: ${Buffer.concat(errors).toString('utf8')}`)));
|
|
47
|
+
child.stdin.end(bytes);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export async function captureContent(root, index, registry, fetcher = fetch) {
|
|
51
|
+
const releases = [];
|
|
52
|
+
for (const e of index.vendors) for (const p of e.packages) for (const v of p.versions) {
|
|
53
|
+
if (!v.integrity) continue;
|
|
54
|
+
const release = contentIdentity({ vendor: e.vendor, package: p.name, source: p.source, ...v });
|
|
55
|
+
const source = validateSubmission(release, index.sources);
|
|
56
|
+
const id = submissionId(release), path = `content/${id}.json`;
|
|
57
|
+
if (existsSync(join(root, path))) {
|
|
58
|
+
contentReceipt(root, release, { path, sha256: digest(read(join(root, path))) });
|
|
59
|
+
releases.push({ package: p.name, version: v.version, path, existing: true });
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const doc = await metadata(p.name, v.version, registry, fetcher);
|
|
63
|
+
const bytes = await artifactBytes(doc, release, registry, fetcher);
|
|
64
|
+
const members = (await archive(bytes, ['-tzf', '-'])).trim().split('\n');
|
|
65
|
+
requireThat(members.filter(name => name === 'package/package.json').length === 1, 'artifact needs one package manifest');
|
|
66
|
+
const pack = JSON.parse(await archive(bytes, ['-xzOf', '-', 'package/package.json']));
|
|
67
|
+
requireThat(pack.name === p.name && pack.version === v.version, 'artifact manifest identity differs');
|
|
68
|
+
const repository = typeof pack.repository === 'string' ? pack.repository : pack.repository?.url;
|
|
69
|
+
requireThat(repository?.replace(/^git\+/, '').replace(/\.git$/, '') === `https://github.com/${source.repository}`,
|
|
70
|
+
'artifact repository differs from registered source');
|
|
71
|
+
const readmes = members.filter(name => /^package\/readme(?:\.md|\.markdown|\.txt)?$/i.test(name));
|
|
72
|
+
requireThat(readmes.length <= 1, 'artifact has ambiguous READMEs');
|
|
73
|
+
const receipt = { schemaVersion: 1, release,
|
|
74
|
+
packageMetadata: {
|
|
75
|
+
description: typeof pack.description === 'string' ? pack.description : null,
|
|
76
|
+
license: typeof pack.license === 'string' ? pack.license : null,
|
|
77
|
+
engines: pack.engines ?? {}, peerDependencies: pack.peerDependencies ?? {},
|
|
78
|
+
repositoryDirectory: typeof pack.repository === 'object' ? pack.repository.directory ?? null : null,
|
|
79
|
+
bugs: typeof pack.bugs === 'string' ? pack.bugs : pack.bugs?.url ?? null,
|
|
80
|
+
},
|
|
81
|
+
readme: readmes.length ? { path: readmes[0], markdown: await archive(bytes, ['-xzOf', '-', readmes[0]]) } : null,
|
|
82
|
+
};
|
|
83
|
+
write(join(root, path), receipt);
|
|
84
|
+
releases.push({ package: p.name, version: v.version, path, existing: false, readme: Boolean(receipt.readme) });
|
|
85
|
+
}
|
|
86
|
+
return { releases, next: 'Commit the captured data with the catalog maintenance change; publication binds it to the snapshot. No assessment was run.' };
|
|
87
|
+
}
|
package/lib/publication.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync } from 'node:f
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { spawnSync } from 'node:child_process';
|
|
4
4
|
import { admit, defaults, digest, loadIndex, read, requireThat, stable, submissionId, validateIndex, write } from './model.mjs';
|
|
5
|
+
import { retainedContent } from './content.mjs';
|
|
5
6
|
|
|
6
7
|
export function git(root, args) {
|
|
7
8
|
const r = spawnSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
@@ -37,7 +38,9 @@ export function build(root, out, evidence = {}) {
|
|
|
37
38
|
const commit = git(root, ['rev-parse', 'HEAD']);
|
|
38
39
|
const version = `0.2.${git(root, ['rev-list', '--first-parent', '--count', 'HEAD'])}`;
|
|
39
40
|
const references = Object.fromEntries(Object.entries(evidence).map(([id, { envelope, ...receipt }]) => [id, receipt]));
|
|
40
|
-
const
|
|
41
|
+
const content = retainedContent(root, index);
|
|
42
|
+
const contentIdentity = Object.keys(content).length ? { content } : {};
|
|
43
|
+
const identity = digest({ evidence: references, sources: index.sources, vendors: index.vendors, recommendations: index.recommendations, revocations: index.revocations, ...contentIdentity });
|
|
41
44
|
mkdirSync(out, { recursive: true });
|
|
42
45
|
write(join(out, 'sources.json'), index.sources);
|
|
43
46
|
write(join(out, 'recommendations.json'), index.recommendations);
|
|
@@ -45,6 +48,11 @@ export function build(root, out, evidence = {}) {
|
|
|
45
48
|
for (const e of index.vendors) write(join(out, 'vendors', `${e.vendor}.json`), e);
|
|
46
49
|
const catalog = { schemaVersion: 1, sourceCommit: commit, digest: identity, versions: index.vendors.flatMap((e) => e.packages.flatMap((p) => p.versions.map((v) => ({ vendor: e.vendor, package: p.name, source: p.source, ...v, evidence: (v.submission ?? v.assessment) ? { submission: v.submission ?? v.assessment, admissionCommit: v.assessmentCommit ?? v.commit, ...(references[v.submission ?? v.assessment] ?? {}) } : null, assessed: Boolean(v.submission ?? v.assessment) })))) };
|
|
47
50
|
write(join(out, 'catalog.json'), catalog);
|
|
51
|
+
if (Object.keys(content).length) {
|
|
52
|
+
catalog.content = content;
|
|
53
|
+
write(join(out, 'catalog.json'), catalog);
|
|
54
|
+
for (const { path } of Object.values(content)) write(join(out, path), read(join(root, path)));
|
|
55
|
+
}
|
|
48
56
|
for (const [id, receipt] of Object.entries(evidence)) write(join(out, 'evidence', `${id}.json`), receipt.envelope);
|
|
49
57
|
const pkg = { ...read(join(root, 'package.json')), version, catalog: { sourceCommit: commit, digest: identity } };
|
|
50
58
|
delete pkg.devDependencies;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/twin-catalog",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.42",
|
|
4
4
|
"description": "The moderated twin distribution: approved versions and submission tooling for independent publishers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,10 +35,11 @@
|
|
|
35
35
|
"lib",
|
|
36
36
|
"runner",
|
|
37
37
|
"docs",
|
|
38
|
-
"evidence"
|
|
38
|
+
"evidence",
|
|
39
|
+
"content"
|
|
39
40
|
],
|
|
40
41
|
"catalog": {
|
|
41
|
-
"sourceCommit": "
|
|
42
|
-
"digest": "
|
|
42
|
+
"sourceCommit": "0bf8d1e4abbdf762531c875c432edf9516edf63b",
|
|
43
|
+
"digest": "5103e721dd9632a05ec4d5348d1b9e668ee092b3edf634c0e4b08f08efb76527"
|
|
43
44
|
}
|
|
44
45
|
}
|
package/runner/prepare.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// No credentials enter this container. This phase downloads data; scripts are disabled.
|
|
2
|
-
import { readFileSync, writeFileSync, mkdirSync, cpSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, cpSync, realpathSync, readdirSync } from 'node:fs';
|
|
3
3
|
import { join, relative } from 'node:path';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
@@ -103,6 +103,10 @@ for (const [path, entry] of Object.entries(consumerLock.packages ?? {})) {
|
|
|
103
103
|
}
|
|
104
104
|
const consumer = { appDir, cli, artifactIntegrity: s.integrity };
|
|
105
105
|
// Retain listing facts from these exact bytes, never the registry's moving latest metadata.
|
|
106
|
+
const readmeNames = readdirSync('/work/unpacked/package').filter(name => /^readme(?:\.md|\.markdown|\.txt)?$/i.test(name));
|
|
107
|
+
requireThat(readmeNames.length <= 1, 'artifact has ambiguous READMEs');
|
|
108
|
+
const readme = readmeNames.length ? { path: `package/${readmeNames[0]}`,
|
|
109
|
+
markdown: readFileSync(join('/work/unpacked/package', readmeNames[0]), 'utf8') } : null;
|
|
106
110
|
const packageMetadata = {
|
|
107
111
|
description: typeof pack.description === 'string' ? pack.description : null,
|
|
108
112
|
license: pack.license,
|
|
@@ -111,5 +115,5 @@ const packageMetadata = {
|
|
|
111
115
|
repositoryDirectory: typeof pack.repository === 'object' ? pack.repository.directory ?? null : null,
|
|
112
116
|
bugs: typeof pack.bugs === 'string' ? pack.bugs : pack.bugs?.url ?? null,
|
|
113
117
|
};
|
|
114
|
-
write('/work/prepared.json', { schemaVersion: 1, submission: s, integrity: s.integrity, provenance, packageMetadata, dependencyLockSha256: digest(readFileSync('/work/package-lock.json', 'utf8')), clientSdkLocks, clientDependencyChoices, tools: policy.tools, consumer, consumerFixture, consumerDependencyLockSha256: digest(readFileSync(join(appDir, 'package-lock.json'), 'utf8')) });
|
|
118
|
+
write('/work/prepared.json', { schemaVersion: 1, submission: s, integrity: s.integrity, provenance, packageMetadata, readme, dependencyLockSha256: digest(readFileSync('/work/package-lock.json', 'utf8')), clientSdkLocks, clientDependencyChoices, tools: policy.tools, consumer, consumerFixture, consumerDependencyLockSha256: digest(readFileSync(join(appDir, 'package-lock.json'), 'utf8')) });
|
|
115
119
|
write('/work/world.json', { id: 'catalog-assessment', network: { egress: [] }, services: [] });
|