@sponson/adapters 0.0.0-stage → 0.5.0
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/LICENSE +202 -0
- package/README.md +4 -2
- package/dist/algolia.d.ts +6 -0
- package/dist/algolia.js +151 -0
- package/dist/algolia.js.map +1 -0
- package/dist/clerk.d.ts +8 -0
- package/dist/clerk.js +107 -0
- package/dist/clerk.js.map +1 -0
- package/dist/cloudflare.d.ts +25 -0
- package/dist/cloudflare.js +310 -0
- package/dist/cloudflare.js.map +1 -0
- package/dist/common.d.ts +73 -0
- package/dist/common.js +140 -0
- package/dist/common.js.map +1 -0
- package/dist/digest.d.ts +46 -0
- package/dist/digest.js +129 -0
- package/dist/digest.js.map +1 -0
- package/dist/digitalocean.d.ts +5 -0
- package/dist/digitalocean.js +243 -0
- package/dist/digitalocean.js.map +1 -0
- package/dist/http-adapter-action.d.ts +63 -0
- package/dist/http-adapter-action.js +369 -0
- package/dist/http-adapter-action.js.map +1 -0
- package/dist/http-adapter-auth.d.ts +88 -0
- package/dist/http-adapter-auth.js +437 -0
- package/dist/http-adapter-auth.js.map +1 -0
- package/dist/http-adapter-client.d.ts +51 -0
- package/dist/http-adapter-client.js +156 -0
- package/dist/http-adapter-client.js.map +1 -0
- package/dist/http-adapter-graphql.d.ts +39 -0
- package/dist/http-adapter-graphql.js +157 -0
- package/dist/http-adapter-graphql.js.map +1 -0
- package/dist/http-adapter-list.d.ts +33 -0
- package/dist/http-adapter-list.js +421 -0
- package/dist/http-adapter-list.js.map +1 -0
- package/dist/http-adapter-resource.d.ts +29 -0
- package/dist/http-adapter-resource.js +462 -0
- package/dist/http-adapter-resource.js.map +1 -0
- package/dist/http-adapter-spec.d.ts +216 -0
- package/dist/http-adapter-spec.js +660 -0
- package/dist/http-adapter-spec.js.map +1 -0
- package/dist/http-adapter.d.ts +16 -0
- package/dist/http-adapter.js +28 -0
- package/dist/http-adapter.js.map +1 -0
- package/dist/http.d.ts +179 -0
- package/dist/http.js +352 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/launchdarkly.d.ts +15 -0
- package/dist/launchdarkly.js +337 -0
- package/dist/launchdarkly.js.map +1 -0
- package/dist/manual.d.ts +13 -0
- package/dist/manual.js +201 -0
- package/dist/manual.js.map +1 -0
- package/dist/neon.d.ts +8 -0
- package/dist/neon.js +167 -0
- package/dist/neon.js.map +1 -0
- package/dist/netlify.d.ts +18 -0
- package/dist/netlify.js +436 -0
- package/dist/netlify.js.map +1 -0
- package/dist/planetscale.d.ts +10 -0
- package/dist/planetscale.js +311 -0
- package/dist/planetscale.js.map +1 -0
- package/dist/providers.d.ts +26 -0
- package/dist/providers.js +36 -0
- package/dist/providers.js.map +1 -0
- package/dist/recipes.d.ts +167 -0
- package/dist/recipes.js +246 -0
- package/dist/recipes.js.map +1 -0
- package/dist/secrets.d.ts +72 -0
- package/dist/secrets.js +476 -0
- package/dist/secrets.js.map +1 -0
- package/dist/sigv4.d.ts +56 -0
- package/dist/sigv4.js +118 -0
- package/dist/sigv4.js.map +1 -0
- package/dist/supabase.d.ts +9 -0
- package/dist/supabase.js +385 -0
- package/dist/supabase.js.map +1 -0
- package/dist/vercel.d.ts +8 -0
- package/dist/vercel.js +475 -0
- package/dist/vercel.js.map +1 -0
- package/dist/xata.d.ts +8 -0
- package/dist/xata.js +142 -0
- package/dist/xata.js.map +1 -0
- package/dist/xml.d.ts +25 -0
- package/dist/xml.js +211 -0
- package/dist/xml.js.map +1 -0
- package/package.json +58 -3
- package/recipes/amplify.yaml +147 -0
- package/recipes/auth0.yaml +178 -0
- package/recipes/azure_swa.yaml +116 -0
- package/recipes/cloud_run.yaml +97 -0
- package/recipes/cloudflare.yaml +108 -0
- package/recipes/cockroachdb.yaml +132 -0
- package/recipes/configcat.yaml +123 -0
- package/recipes/datadog.yaml +136 -0
- package/recipes/firebase.yaml +84 -0
- package/recipes/flagsmith.yaml +98 -0
- package/recipes/fly.yaml +97 -0
- package/recipes/fly_machines.yaml +67 -0
- package/recipes/gcs.yaml +102 -0
- package/recipes/github.yaml +123 -0
- package/recipes/growthbook.yaml +124 -0
- package/recipes/heroku.yaml +98 -0
- package/recipes/honeycomb.yaml +89 -0
- package/recipes/inngest.yaml +97 -0
- package/recipes/kinde.yaml +120 -0
- package/recipes/mongodb_atlas.yaml +119 -0
- package/recipes/okta.yaml +177 -0
- package/recipes/posthog.yaml +127 -0
- package/recipes/postmark.yaml +105 -0
- package/recipes/postmark_server.yaml +93 -0
- package/recipes/prisma.yaml +150 -0
- package/recipes/qstash.yaml +134 -0
- package/recipes/railway.yaml +130 -0
- package/recipes/render.yaml +103 -0
- package/recipes/resend.yaml +130 -0
- package/recipes/s3.yaml +108 -0
- package/recipes/sendgrid.yaml +165 -0
- package/recipes/sentry.yaml +158 -0
- package/recipes/split.yaml +121 -0
- package/recipes/statsig.yaml +124 -0
- package/recipes/stripe.yaml +310 -0
- package/recipes/stytch.yaml +113 -0
- package/recipes/svix.yaml +109 -0
- package/recipes/turso.yaml +98 -0
- package/recipes/unleash.yaml +149 -0
- package/recipes/upstash.yaml +130 -0
- package/recipes/vercel.yaml +116 -0
- package/recipes/workos.yaml +70 -0
package/dist/xata.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Xata adapter (the Postgres platform): a copy-on-write branch per scope, child of a parent branch. A new branch
|
|
3
|
+
* takes a moment to come up, so `apply` waits for it to be healthy, then reads its credentials: the wait and the
|
|
4
|
+
* second request are why this is an adapter and not an `http` recipe (ADR 0017, "No polling"). The API assumptions
|
|
5
|
+
* it relies on are numbered XA1… at the top of packages/sim/src/routes/xata.ts.
|
|
6
|
+
*
|
|
7
|
+
* - Key: `branch:<name>`. Id: Xata's branch id. The organization and project are the provider block.
|
|
8
|
+
* - Hash: the name only. The parent is used when the branch is created; a branch cannot be moved to another
|
|
9
|
+
* parent, so changing `parent_id` later changes nothing, and a deleted branch is `missing` (re-created by the
|
|
10
|
+
* next apply, from the parent as it is then).
|
|
11
|
+
* - Outputs: the branch id, and its connection string (sensitive), read from the credentials endpoint on every run
|
|
12
|
+
* (XA6), so dependents in later runs get it too.
|
|
13
|
+
*/
|
|
14
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
15
|
+
import { SponsonError, canonicalJson, markerKind, sha256 } from "@sponson/core";
|
|
16
|
+
// Only the stable authoring API exported from `@sponson/adapters` (listed in CONTRIBUTING.md).
|
|
17
|
+
import { assertNoPending, clientFor, deleteIgnoringNotFound, optionalEnv, paramError, requireEnv, requireProvider, stringParam } from "./common.js";
|
|
18
|
+
import { ShapeError, isObject, records } from "./http.js";
|
|
19
|
+
const ADAPTER = "xata";
|
|
20
|
+
/** The environment Xata reads; declared once, used by the code below and by the generated docs (`about`). */
|
|
21
|
+
const ABOUT = { credentialEnv: "XATA_API_KEY", baseUrlEnv: "XATA_API_URL", title: "Xata", category: "databases", detect: { deps: ["@xata.io/"], env: ["XATA_*"], files: [".xatarc"] } };
|
|
22
|
+
/** Xata's API base URL (XA1). `XATA_API_URL` overrides it; tests and scenarios point that at the sim. */
|
|
23
|
+
export const XATA_DEFAULT_API_URL = "https://api.xata.tech";
|
|
24
|
+
/** How often a new branch is polled, and for how long (milliseconds; overridable for tests). */
|
|
25
|
+
const POLL_MS = { env: "SPONSON_XATA_POLL_MS", fallback: 2000 };
|
|
26
|
+
const READY_TIMEOUT_MS = { env: "SPONSON_XATA_READY_TIMEOUT_MS", fallback: 10 * 60 * 1000 };
|
|
27
|
+
function msFromEnv(env, s) {
|
|
28
|
+
const raw = optionalEnv(env, s.env);
|
|
29
|
+
const n = Number(raw);
|
|
30
|
+
return raw !== undefined && Number.isFinite(n) && n >= 0 ? n : s.fallback;
|
|
31
|
+
}
|
|
32
|
+
function client(actx) {
|
|
33
|
+
const token = requireEnv(actx.env, ABOUT.credentialEnv, ADAPTER);
|
|
34
|
+
const org = requireProvider(actx, "organization", ADAPTER);
|
|
35
|
+
const project = requireProvider(actx, "project", ADAPTER);
|
|
36
|
+
const api = clientFor(actx, ADAPTER, { baseUrl: optionalEnv(actx.env, ABOUT.baseUrlEnv) ?? XATA_DEFAULT_API_URL, token });
|
|
37
|
+
return { api, base: `/organizations/${enc(org)}/projects/${enc(project)}/branches` };
|
|
38
|
+
}
|
|
39
|
+
function enc(s) {
|
|
40
|
+
return encodeURIComponent(s);
|
|
41
|
+
}
|
|
42
|
+
const PREFIX = "branch:";
|
|
43
|
+
function branchRecord(b) {
|
|
44
|
+
return { key: `${PREFIX}${b.name}`, id: b.id, hash: sha256(canonicalJson({ name: b.name })), label: `Xata branch ${b.name}` };
|
|
45
|
+
}
|
|
46
|
+
/** The branch named `name`, or null (XA3: names are not unique, so more than one is refused, never guessed). */
|
|
47
|
+
async function findBranch(c, name) {
|
|
48
|
+
const list = await c.api.get(c.base, (b) => {
|
|
49
|
+
if (!isObject(b))
|
|
50
|
+
throw new ShapeError("expected `{ branches }`");
|
|
51
|
+
return records(b.branches, "`branches`", ["id", "name"]);
|
|
52
|
+
});
|
|
53
|
+
const hits = list.filter((b) => b.name === name);
|
|
54
|
+
if (hits.length > 1)
|
|
55
|
+
throw paramError(ADAPTER, `${hits.length} branches are named ${name} in the project; rename one or give this line another name`, "name");
|
|
56
|
+
return hits[0] ? { id: hits[0].id, name: hits[0].name } : null;
|
|
57
|
+
}
|
|
58
|
+
/** The connection string from the credentials endpoint (XA6). */
|
|
59
|
+
async function connectionString(c, id) {
|
|
60
|
+
return c.api.get(`${c.base}/${enc(id)}/credentials?username=xata`, (b) => {
|
|
61
|
+
if (!isObject(b) || typeof b.connectionString !== "string" || b.connectionString === "")
|
|
62
|
+
throw new ShapeError("expected `{ connectionString }`");
|
|
63
|
+
return b.connectionString;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async function outputsOf(c, b) {
|
|
67
|
+
return { branch_id: b.id, connection_string: await connectionString(c, b.id) };
|
|
68
|
+
}
|
|
69
|
+
/** `status.statusType` of a branch (XA5), or "" when the answer has none yet. */
|
|
70
|
+
function statusType(body) {
|
|
71
|
+
const status = isObject(body) ? body.status : undefined;
|
|
72
|
+
return isObject(status) && typeof status.statusType === "string" ? status.statusType : "";
|
|
73
|
+
}
|
|
74
|
+
/** Poll the branch until it is healthy (XA5); FAULT fails, a timeout is WAIT_TIMEOUT that the next run resumes. */
|
|
75
|
+
async function waitHealthy(actx, c, b) {
|
|
76
|
+
const deadline = Date.now() + msFromEnv(actx.env, READY_TIMEOUT_MS);
|
|
77
|
+
for (;;) {
|
|
78
|
+
const type = statusType(await c.api.get(`${c.base}/${enc(b.id)}`));
|
|
79
|
+
if (/HEALTHY$/.test(type))
|
|
80
|
+
return;
|
|
81
|
+
if (/FAULT$/.test(type))
|
|
82
|
+
throw new SponsonError("PROVIDER_INVALID", `xata: branch ${b.name} reports ${type} while coming up`, { adapter: ADAPTER, branch: b.name });
|
|
83
|
+
if (Date.now() > deadline) {
|
|
84
|
+
throw new SponsonError("WAIT_TIMEOUT", `xata: branch ${b.name} is not healthy after ${msFromEnv(actx.env, READY_TIMEOUT_MS)}ms (${READY_TIMEOUT_MS.env}); run again to keep waiting`, { adapter: ADAPTER, branch: b.name });
|
|
85
|
+
}
|
|
86
|
+
actx.log(`branch ${b.name} not healthy yet (${type || "no status"})`);
|
|
87
|
+
await sleep(msFromEnv(actx.env, POLL_MS));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const branch = {
|
|
91
|
+
outputs: { branch_id: { available: "immediate" }, connection_string: { available: "immediate", sensitive: true } },
|
|
92
|
+
async read(actx, params) {
|
|
93
|
+
if (markerKind(params.name) !== null)
|
|
94
|
+
return null;
|
|
95
|
+
const c = client(actx);
|
|
96
|
+
const found = await findBranch(c, stringParam(params, "name", ADAPTER));
|
|
97
|
+
if (!found)
|
|
98
|
+
return null;
|
|
99
|
+
return { resources: [branchRecord(found)], outputs: await outputsOf(c, found) };
|
|
100
|
+
},
|
|
101
|
+
diff(live, params) {
|
|
102
|
+
const name = params.name;
|
|
103
|
+
const key = markerKind(name) !== null ? `${PREFIX}(pending)` : `${PREFIX}${String(name)}`;
|
|
104
|
+
const label = `Xata branch ${String(name)}`;
|
|
105
|
+
if (live?.resources.some((r) => r.key === key))
|
|
106
|
+
return [{ key, kind: "unchanged", label }];
|
|
107
|
+
const parent = params.parent_id;
|
|
108
|
+
const after = markerKind(parent) !== null ? { state: "pending", ref: String(parent) } : { state: "literal", value: `child of ${String(parent)}` };
|
|
109
|
+
return [{ key, kind: "create", label, before: { state: "absent" }, after }];
|
|
110
|
+
},
|
|
111
|
+
async apply(actx, params, live) {
|
|
112
|
+
assertNoPending(params, ADAPTER);
|
|
113
|
+
const name = stringParam(params, "name", ADAPTER);
|
|
114
|
+
const parent = stringParam(params, "parent_id", ADAPTER);
|
|
115
|
+
const key = `${PREFIX}${name}`;
|
|
116
|
+
if (live?.resources.some((r) => r.key === key))
|
|
117
|
+
return { resources: live.resources, outputs: live.outputs, created: [] };
|
|
118
|
+
const c = client(actx);
|
|
119
|
+
// Announce the create before sending it; a create whose answer was lost is found by name next time (XA3).
|
|
120
|
+
await actx.intend([key]);
|
|
121
|
+
actx.log(`create branch ${name} from ${parent}`);
|
|
122
|
+
const created = await c.api.post(c.base, { mode: "inherit", parentID: parent, name }, (b) => {
|
|
123
|
+
const [r] = records([b], "the branch", ["id", "name"]);
|
|
124
|
+
return { id: r.id, name: r.name };
|
|
125
|
+
});
|
|
126
|
+
await waitHealthy(actx, c, created);
|
|
127
|
+
return { resources: [branchRecord(created)], outputs: await outputsOf(c, created), created: [key] };
|
|
128
|
+
},
|
|
129
|
+
async destroy(actx, resources) {
|
|
130
|
+
const c = client(actx);
|
|
131
|
+
// An intent the engine could not locate has no id: nothing is deleted on a guess (names are not unique, XA3).
|
|
132
|
+
for (const r of resources)
|
|
133
|
+
if (r.id !== "")
|
|
134
|
+
await deleteIgnoringNotFound(c.api, `${c.base}/${enc(r.id)}`);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* The Xata adapter (`adapter: xata` in a plan). Registered in `createRegistry()`; needs `XATA_API_KEY` and
|
|
139
|
+
* `providers.xata.organization` and `.project`.
|
|
140
|
+
*/
|
|
141
|
+
export const xataAdapter = { name: ADAPTER, ops: { branch }, about: ABOUT };
|
|
142
|
+
//# sourceMappingURL=xata.js.map
|
package/dist/xata.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xata.js","sourceRoot":"","sources":["../src/xata.ts"],"names":[],"mappings":"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"}
|
package/dist/xml.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal XML codec for the generic `http` adapter's `encoding: xml` (S3-style configuration documents such as a
|
|
3
|
+
* bucket's `CORSConfiguration`), mapping XML to the JSON shapes the adapter already works with:
|
|
4
|
+
*
|
|
5
|
+
* - an element with child elements is a map of child name → value; a child that repeats is a list of values;
|
|
6
|
+
* - an element with only text is that text, as a string (XML has no numbers or booleans); an empty element is "";
|
|
7
|
+
* - attributes are `@name` keys (`@xmlns`), and the text of an element that also has attributes is `#text`.
|
|
8
|
+
*
|
|
9
|
+
* Encoding is the inverse: the body is a map with one key (the root element), lists become repeated elements,
|
|
10
|
+
* `null` leaves an element out. A single repeated element therefore reads back as a value, not a list of one.
|
|
11
|
+
*
|
|
12
|
+
* Safe by construction: no DTDs (a `<!DOCTYPE` or `<!ENTITY` is refused, so no external entities and no entity
|
|
13
|
+
* expansion), only the five predefined entities and numeric character references, a depth limit, and no
|
|
14
|
+
* namespace processing (prefixed names are kept as written).
|
|
15
|
+
*/
|
|
16
|
+
/** Nesting deeper than this is refused rather than recursed into. */
|
|
17
|
+
export declare const XML_MAX_DEPTH = 64;
|
|
18
|
+
/** Thrown for a document (or a body) this codec does not handle. */
|
|
19
|
+
export declare class XmlError extends Error {
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
/** A body as an XML document: a map with exactly one key, the root element. */
|
|
23
|
+
export declare function xmlEncode(body: unknown): string;
|
|
24
|
+
/** An XML document as `{ <root>: <value> }`. */
|
|
25
|
+
export declare function xmlDecode(xml: string): Record<string, unknown>;
|
package/dist/xml.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal XML codec for the generic `http` adapter's `encoding: xml` (S3-style configuration documents such as a
|
|
3
|
+
* bucket's `CORSConfiguration`), mapping XML to the JSON shapes the adapter already works with:
|
|
4
|
+
*
|
|
5
|
+
* - an element with child elements is a map of child name → value; a child that repeats is a list of values;
|
|
6
|
+
* - an element with only text is that text, as a string (XML has no numbers or booleans); an empty element is "";
|
|
7
|
+
* - attributes are `@name` keys (`@xmlns`), and the text of an element that also has attributes is `#text`.
|
|
8
|
+
*
|
|
9
|
+
* Encoding is the inverse: the body is a map with one key (the root element), lists become repeated elements,
|
|
10
|
+
* `null` leaves an element out. A single repeated element therefore reads back as a value, not a list of one.
|
|
11
|
+
*
|
|
12
|
+
* Safe by construction: no DTDs (a `<!DOCTYPE` or `<!ENTITY` is refused, so no external entities and no entity
|
|
13
|
+
* expansion), only the five predefined entities and numeric character references, a depth limit, and no
|
|
14
|
+
* namespace processing (prefixed names are kept as written).
|
|
15
|
+
*/
|
|
16
|
+
/** Nesting deeper than this is refused rather than recursed into. */
|
|
17
|
+
export const XML_MAX_DEPTH = 64;
|
|
18
|
+
const NAME = /^[A-Za-z_][A-Za-z0-9_.-]*(?::[A-Za-z_][A-Za-z0-9_.-]*)?$/;
|
|
19
|
+
/** Thrown for a document (or a body) this codec does not handle. */
|
|
20
|
+
export class XmlError extends Error {
|
|
21
|
+
constructor(message) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "XmlError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function escapeText(s) {
|
|
27
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
28
|
+
}
|
|
29
|
+
function escapeAttr(s) {
|
|
30
|
+
return escapeText(s).replace(/"/g, """);
|
|
31
|
+
}
|
|
32
|
+
function scalar(v, name) {
|
|
33
|
+
if (typeof v === "string")
|
|
34
|
+
return v;
|
|
35
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
36
|
+
return String(v);
|
|
37
|
+
throw new XmlError(`\`${name}\` must be a map, a list, a string, a number or a boolean`);
|
|
38
|
+
}
|
|
39
|
+
function checkName(name) {
|
|
40
|
+
if (!NAME.test(name))
|
|
41
|
+
throw new XmlError(`\`${name}\` is not an XML element name`);
|
|
42
|
+
}
|
|
43
|
+
function element(name, v, depth) {
|
|
44
|
+
if (depth > XML_MAX_DEPTH)
|
|
45
|
+
throw new XmlError(`nested deeper than ${XML_MAX_DEPTH} elements`);
|
|
46
|
+
if (v === null || v === undefined)
|
|
47
|
+
return "";
|
|
48
|
+
if (Array.isArray(v))
|
|
49
|
+
return v.map((x) => element(name, x, depth)).join("");
|
|
50
|
+
checkName(name);
|
|
51
|
+
if (typeof v !== "object")
|
|
52
|
+
return `<${name}>${escapeText(scalar(v, name))}</${name}>`;
|
|
53
|
+
let attrs = "";
|
|
54
|
+
let inner = "";
|
|
55
|
+
for (const [k, x] of Object.entries(v)) {
|
|
56
|
+
if (k.startsWith("@")) {
|
|
57
|
+
checkName(k.slice(1));
|
|
58
|
+
attrs += ` ${k.slice(1)}="${escapeAttr(scalar(x, k))}"`;
|
|
59
|
+
}
|
|
60
|
+
else if (k === "#text")
|
|
61
|
+
inner += escapeText(scalar(x, k));
|
|
62
|
+
else
|
|
63
|
+
inner += element(k, x, depth + 1);
|
|
64
|
+
}
|
|
65
|
+
return `<${name}${attrs}>${inner}</${name}>`;
|
|
66
|
+
}
|
|
67
|
+
/** A body as an XML document: a map with exactly one key, the root element. */
|
|
68
|
+
export function xmlEncode(body) {
|
|
69
|
+
if (typeof body !== "object" || body === null || Array.isArray(body) || Object.keys(body).length !== 1) {
|
|
70
|
+
throw new XmlError("an XML body must be a map with exactly one key: the root element, e.g. { CORSConfiguration: { … } }");
|
|
71
|
+
}
|
|
72
|
+
const [root, value] = Object.entries(body)[0];
|
|
73
|
+
return `<?xml version="1.0" encoding="UTF-8"?>${element(root, value ?? "", 0)}`;
|
|
74
|
+
}
|
|
75
|
+
const ENTITIES = { lt: "<", gt: ">", amp: "&", quot: '"', apos: "'" };
|
|
76
|
+
/** Text with its entity and character references replaced. */
|
|
77
|
+
function decodeEntities(s) {
|
|
78
|
+
return s.replace(/&(#x[0-9A-Fa-f]+|#[0-9]+|[A-Za-z]+);/g, (_m, ref) => {
|
|
79
|
+
if (ref.startsWith("#x"))
|
|
80
|
+
return String.fromCodePoint(parseInt(ref.slice(2), 16));
|
|
81
|
+
if (ref.startsWith("#"))
|
|
82
|
+
return String.fromCodePoint(parseInt(ref.slice(1), 10));
|
|
83
|
+
const v = ENTITIES[ref];
|
|
84
|
+
if (v === undefined)
|
|
85
|
+
throw new XmlError(`unknown entity &${ref};`);
|
|
86
|
+
return v;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function valueOf(e) {
|
|
90
|
+
if (e.children.length === 0) {
|
|
91
|
+
if (Object.keys(e.attrs).length === 0)
|
|
92
|
+
return e.text;
|
|
93
|
+
return { ...prefixed(e.attrs), ...(e.text.trim() !== "" ? { "#text": e.text } : {}) };
|
|
94
|
+
}
|
|
95
|
+
const groups = new Map();
|
|
96
|
+
for (const [name, v] of e.children) {
|
|
97
|
+
const list = groups.get(name);
|
|
98
|
+
if (list)
|
|
99
|
+
list.push(v);
|
|
100
|
+
else
|
|
101
|
+
groups.set(name, [v]);
|
|
102
|
+
}
|
|
103
|
+
const out = prefixed(e.attrs);
|
|
104
|
+
for (const [name, values] of groups)
|
|
105
|
+
out[name] = values.length === 1 ? values[0] : values;
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
function prefixed(attrs) {
|
|
109
|
+
return Object.fromEntries(Object.entries(attrs).map(([k, v]) => [`@${k}`, v]));
|
|
110
|
+
}
|
|
111
|
+
const ATTR = /([A-Za-z_][\w.:-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
112
|
+
function parseAttrs(s) {
|
|
113
|
+
const out = {};
|
|
114
|
+
for (const m of s.matchAll(ATTR))
|
|
115
|
+
out[m[1]] = decodeEntities(m[2] ?? m[3] ?? "");
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
/** Skip a construct starting at `i` that holds no data: declaration, processing instruction, comment. */
|
|
119
|
+
function skipMarkup(xml, i) {
|
|
120
|
+
const ends = [
|
|
121
|
+
["<?", "?>"],
|
|
122
|
+
["<!--", "-->"],
|
|
123
|
+
];
|
|
124
|
+
for (const [start, end] of ends) {
|
|
125
|
+
if (xml.startsWith(start, i)) {
|
|
126
|
+
const j = xml.indexOf(end, i + start.length);
|
|
127
|
+
if (j < 0)
|
|
128
|
+
throw new XmlError(`unterminated ${start}`);
|
|
129
|
+
return j + end.length;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return -1;
|
|
133
|
+
}
|
|
134
|
+
/** Handle a tag at `i` (`<…`); returns the index after it. */
|
|
135
|
+
function tag(xml, i, stack, done) {
|
|
136
|
+
const skipped = skipMarkup(xml, i);
|
|
137
|
+
if (skipped >= 0)
|
|
138
|
+
return skipped;
|
|
139
|
+
if (xml.startsWith("<!DOCTYPE", i) || xml.startsWith("<!ENTITY", i))
|
|
140
|
+
throw new XmlError("DTDs and entity declarations are not accepted");
|
|
141
|
+
if (xml.startsWith("<![CDATA[", i))
|
|
142
|
+
return cdata(xml, i, stack);
|
|
143
|
+
const end = xml.indexOf(">", i);
|
|
144
|
+
if (end < 0)
|
|
145
|
+
throw new XmlError("unterminated tag");
|
|
146
|
+
const body = xml.slice(i + 1, end);
|
|
147
|
+
if (body.startsWith("/")) {
|
|
148
|
+
closingTag(body.slice(1).trim(), stack, done);
|
|
149
|
+
return end + 1;
|
|
150
|
+
}
|
|
151
|
+
const selfClosing = body.endsWith("/");
|
|
152
|
+
const inner = selfClosing ? body.slice(0, -1) : body;
|
|
153
|
+
const name = /^[^\s/>]+/.exec(inner)?.[0] ?? "";
|
|
154
|
+
if (!NAME.test(name))
|
|
155
|
+
throw new XmlError(`\`${name}\` is not an XML element name`);
|
|
156
|
+
if (stack.length >= XML_MAX_DEPTH)
|
|
157
|
+
throw new XmlError(`nested deeper than ${XML_MAX_DEPTH} elements`);
|
|
158
|
+
const open = { name, attrs: parseAttrs(inner.slice(name.length)), children: [], text: "" };
|
|
159
|
+
if (selfClosing)
|
|
160
|
+
close(open, stack, done);
|
|
161
|
+
else
|
|
162
|
+
stack.push(open);
|
|
163
|
+
return end + 1;
|
|
164
|
+
}
|
|
165
|
+
/** A CDATA section's text, appended to the element it is in; the index after it. */
|
|
166
|
+
function cdata(xml, i, stack) {
|
|
167
|
+
const j = xml.indexOf("]]>", i);
|
|
168
|
+
if (j < 0 || stack.length === 0)
|
|
169
|
+
throw new XmlError("misplaced or unterminated CDATA section");
|
|
170
|
+
stack[stack.length - 1].text += xml.slice(i + 9, j);
|
|
171
|
+
return j + 3;
|
|
172
|
+
}
|
|
173
|
+
function closingTag(name, stack, done) {
|
|
174
|
+
const open = stack.pop();
|
|
175
|
+
if (!open || open.name !== name)
|
|
176
|
+
throw new XmlError(`unexpected closing tag </${name}>`);
|
|
177
|
+
close(open, stack, done);
|
|
178
|
+
}
|
|
179
|
+
function close(open, stack, done) {
|
|
180
|
+
const value = valueOf(open);
|
|
181
|
+
const parent = stack[stack.length - 1];
|
|
182
|
+
if (parent)
|
|
183
|
+
parent.children.push([open.name, value]);
|
|
184
|
+
else
|
|
185
|
+
done({ name: open.name, value });
|
|
186
|
+
}
|
|
187
|
+
/** An XML document as `{ <root>: <value> }`. */
|
|
188
|
+
export function xmlDecode(xml) {
|
|
189
|
+
const stack = [];
|
|
190
|
+
let root;
|
|
191
|
+
let i = 0;
|
|
192
|
+
while (i < xml.length) {
|
|
193
|
+
const lt = xml.indexOf("<", i);
|
|
194
|
+
const text = xml.slice(i, lt < 0 ? xml.length : lt);
|
|
195
|
+
if (stack.length > 0)
|
|
196
|
+
stack[stack.length - 1].text += decodeEntities(text);
|
|
197
|
+
else if (text.trim() !== "")
|
|
198
|
+
throw new XmlError("text outside the root element");
|
|
199
|
+
if (lt < 0)
|
|
200
|
+
break;
|
|
201
|
+
if (root && skipMarkup(xml, lt) < 0)
|
|
202
|
+
throw new XmlError("more than one root element");
|
|
203
|
+
i = tag(xml, lt, stack, (r) => (root = r));
|
|
204
|
+
}
|
|
205
|
+
if (stack.length > 0)
|
|
206
|
+
throw new XmlError(`unclosed element <${stack[stack.length - 1].name}>`);
|
|
207
|
+
if (!root)
|
|
208
|
+
throw new XmlError("no root element");
|
|
209
|
+
return { [root.name]: root.value };
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=xml.js.map
|
package/dist/xml.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml.js","sourceRoot":"","sources":["../src/xml.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sponson/adapters",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "The built-in resource adapters and secret sources for Sponson.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"sponson",
|
|
7
|
+
"release",
|
|
8
|
+
"preview-environments",
|
|
9
|
+
"deployment",
|
|
10
|
+
"ci",
|
|
11
|
+
"vercel",
|
|
12
|
+
"neon",
|
|
13
|
+
"clerk",
|
|
14
|
+
"adapters",
|
|
15
|
+
"secrets",
|
|
16
|
+
"recipes"
|
|
17
|
+
],
|
|
18
|
+
"license": "Apache-2.0",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/MishaBear94/Sponson.git",
|
|
22
|
+
"directory": "packages/adapters"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=22"
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"yaml": "^2.8.1",
|
|
38
|
+
"@sponson/core": "0.5.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@sponson/sim": "0.5.0"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist",
|
|
45
|
+
"!dist/.tsbuildinfo",
|
|
46
|
+
"recipes",
|
|
47
|
+
"README.md",
|
|
48
|
+
"LICENSE"
|
|
49
|
+
],
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public",
|
|
52
|
+
"provenance": true
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://sponson.mintlify.site",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/MishaBear94/Sponson/issues"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsc -b"
|
|
60
|
+
}
|
|
6
61
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# AWS Amplify Hosting API recipes. Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
|
|
3
|
+
provider: amplify
|
|
4
|
+
title: AWS Amplify Hosting
|
|
5
|
+
category: deploy
|
|
6
|
+
verified_on: "2026-10-11"
|
|
7
|
+
docs:
|
|
8
|
+
- title: CreateBranch
|
|
9
|
+
url: https://docs.aws.amazon.com/amplify/latest/APIReference/API_CreateBranch.html
|
|
10
|
+
- title: GetBranch
|
|
11
|
+
url: https://docs.aws.amazon.com/amplify/latest/APIReference/API_GetBranch.html
|
|
12
|
+
- title: UpdateBranch
|
|
13
|
+
url: https://docs.aws.amazon.com/amplify/latest/APIReference/API_UpdateBranch.html
|
|
14
|
+
- title: DeleteBranch
|
|
15
|
+
url: https://docs.aws.amazon.com/amplify/latest/APIReference/API_DeleteBranch.html
|
|
16
|
+
- title: Amplify endpoints and quotas
|
|
17
|
+
url: https://docs.aws.amazon.com/general/latest/gr/amplify.html
|
|
18
|
+
- title: Create a signed AWS API request (SigV4)
|
|
19
|
+
url: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html
|
|
20
|
+
api:
|
|
21
|
+
base_url: https://amplify.us-east-1.amazonaws.com
|
|
22
|
+
base_url_env: AMPLIFY_API_URL
|
|
23
|
+
auth:
|
|
24
|
+
aws_sigv4: { region: us-east-1, service: amplify, access_key_id_env: AWS_ACCESS_KEY_ID, secret_access_key_env: AWS_SECRET_ACCESS_KEY }
|
|
25
|
+
detect:
|
|
26
|
+
files: [amplify.yml]
|
|
27
|
+
starter:
|
|
28
|
+
- op: branch_variable
|
|
29
|
+
values: { branch_name: "${ctx.git.branch}" }
|
|
30
|
+
where:
|
|
31
|
+
app_id: "Amplify console → your app → App settings → General → App ID (`d…`), or `aws amplify list-apps --query 'apps[].appId'`"
|
|
32
|
+
assumptions:
|
|
33
|
+
- id: AM1
|
|
34
|
+
verified: true
|
|
35
|
+
text: "The Amplify API is regional (`https://amplify.<region>.amazonaws.com`) and signed with SigV4 for the service `amplify`. The recipe defaults to `us-east-1`; an app in another region sets `base_url` and `auth` (with its `region`) in the provider block, and temporary credentials (a CI role) add `session_token_env: AWS_SESSION_TOKEN` there."
|
|
36
|
+
source: https://docs.aws.amazon.com/general/latest/gr/amplify.html
|
|
37
|
+
- id: AM2
|
|
38
|
+
verified: true
|
|
39
|
+
text: "`POST /apps/{appId}/branches` (CreateBranch) creates a branch from `branchName` (required) and optional `description`, `stage` (PRODUCTION, BETA, DEVELOPMENT, EXPERIMENTAL, PULL_REQUEST), `enableAutoBuild`, `environmentVariables`, …; it answers 200 with `{ branch }`."
|
|
40
|
+
source: https://docs.aws.amazon.com/amplify/latest/APIReference/API_CreateBranch.html
|
|
41
|
+
- id: AM3
|
|
42
|
+
verified: true
|
|
43
|
+
text: "`GET /apps/{appId}/branches/{branchName}` (GetBranch) answers `{ branch }` with `branchName`, `stage`, `description`, `enableAutoBuild` and `environmentVariables` (a map of string to string)."
|
|
44
|
+
source: https://docs.aws.amazon.com/amplify/latest/APIReference/API_GetBranch.html
|
|
45
|
+
- id: AM4
|
|
46
|
+
verified: true
|
|
47
|
+
text: "`POST /apps/{appId}/branches/{branchName}` (UpdateBranch) takes the same optional fields and answers `{ branch }`; `environmentVariables` is the branch's whole map of variables."
|
|
48
|
+
source: https://docs.aws.amazon.com/amplify/latest/APIReference/API_UpdateBranch.html
|
|
49
|
+
- id: AM5
|
|
50
|
+
verified: true
|
|
51
|
+
text: "`DELETE /apps/{appId}/branches/{branchName}` (DeleteBranch) deletes a branch; an unknown app or branch is 404 `NotFoundException`."
|
|
52
|
+
source: https://docs.aws.amazon.com/amplify/latest/APIReference/API_DeleteBranch.html
|
|
53
|
+
- id: AM6
|
|
54
|
+
verified: false
|
|
55
|
+
text: "UpdateBranch leaves the fields it is not sent as they are (so the branch op's update does not reset the variables, and the variable op's write does not reset the branch's settings), while an `environmentVariables` it is sent replaces the whole map, as the sim models it (assumption A4 of packages/sim/src/routes/aws.ts)."
|
|
56
|
+
- id: AM7
|
|
57
|
+
verified: false
|
|
58
|
+
text: "A build that ran before a variable was written does not see it: Sponson does not start a new job (StartJob), so order the variable lines before the branch's first build (`enable_auto_build: false` and a CI-started job, or the branch line, then the variables, then the push). The branches Amplify's own pull request previews make are not modelled; this recipe manages a branch the plan names."
|
|
59
|
+
ops:
|
|
60
|
+
branch:
|
|
61
|
+
kind: resource
|
|
62
|
+
title: Branch
|
|
63
|
+
summary: "An Amplify branch named by the plan (the git branch of the pull request, `${ctx.git.branch}`), created with CreateBranch and deleted on destroy. Its `stage`, `description` and auto-build setting are compared: a console edit is drift. Variables on it are `amplify.branch_variable` lines."
|
|
64
|
+
covers: [amplify-branch]
|
|
65
|
+
params:
|
|
66
|
+
app_id:
|
|
67
|
+
type: string
|
|
68
|
+
required: true
|
|
69
|
+
pattern: "^d[a-z0-9]+$"
|
|
70
|
+
description: The Amplify app's id.
|
|
71
|
+
example: d1demo
|
|
72
|
+
branch_name:
|
|
73
|
+
type: string
|
|
74
|
+
required: true
|
|
75
|
+
description: The branch's name, as the repository names it.
|
|
76
|
+
example: "${ctx.scope}"
|
|
77
|
+
stage:
|
|
78
|
+
type: string
|
|
79
|
+
enum: [PRODUCTION, BETA, DEVELOPMENT, EXPERIMENTAL, PULL_REQUEST]
|
|
80
|
+
description: The branch's stage.
|
|
81
|
+
example: PULL_REQUEST
|
|
82
|
+
description:
|
|
83
|
+
type: string
|
|
84
|
+
description: The branch's description.
|
|
85
|
+
example: "Preview of ${ctx.scope}"
|
|
86
|
+
enable_auto_build:
|
|
87
|
+
type: boolean
|
|
88
|
+
description: Build automatically on every push (false lets CI start the build after the variables are written; AM7).
|
|
89
|
+
http:
|
|
90
|
+
read: { path: "/apps/{app_id}/branches/{branch_name}" }
|
|
91
|
+
create:
|
|
92
|
+
path: "/apps/{app_id}/branches"
|
|
93
|
+
body: { branchName: { param: branch_name } }
|
|
94
|
+
update: { method: POST }
|
|
95
|
+
item_path: /branch
|
|
96
|
+
id_path: /branchName
|
|
97
|
+
fields:
|
|
98
|
+
stage: { param: stage }
|
|
99
|
+
description: { param: description }
|
|
100
|
+
enableAutoBuild: { param: enable_auto_build }
|
|
101
|
+
sim:
|
|
102
|
+
id_from: branchName
|
|
103
|
+
live:
|
|
104
|
+
params: { app_id: SPONSON_LIVE_AMPLIFY_APP_ID }
|
|
105
|
+
branch_variable:
|
|
106
|
+
kind: list_item
|
|
107
|
+
title: Branch environment variable
|
|
108
|
+
summary: "One entry of a branch's `environmentVariables`, by read-modify-write of the whole map (UpdateBranch replaces the map it is sent); other variables are left alone, and the branch is locked while Sponson writes it. A branch that is not there yet reads as having no variables, so a plan that also creates the branch shows a create. Builds started before the write do not see it (AM7)."
|
|
109
|
+
covers: [amplify-branch]
|
|
110
|
+
params:
|
|
111
|
+
app_id:
|
|
112
|
+
type: string
|
|
113
|
+
required: true
|
|
114
|
+
pattern: "^d[a-z0-9]+$"
|
|
115
|
+
description: The Amplify app's id.
|
|
116
|
+
example: d1demo
|
|
117
|
+
branch_name:
|
|
118
|
+
type: string
|
|
119
|
+
required: true
|
|
120
|
+
description: The branch's name (a `{ from }` of the `amplify.branch` line orders the two).
|
|
121
|
+
example: "${ctx.scope}"
|
|
122
|
+
name:
|
|
123
|
+
type: string
|
|
124
|
+
required: true
|
|
125
|
+
description: The variable's name.
|
|
126
|
+
example: API_URL
|
|
127
|
+
value:
|
|
128
|
+
type: string
|
|
129
|
+
required: true
|
|
130
|
+
description: The variable's value.
|
|
131
|
+
example: "https://api-${ctx.scope}.example.app"
|
|
132
|
+
http:
|
|
133
|
+
parent: { path: "/apps/{app_id}/branches/{branch_name}", method: POST, send: collection, item_path: /branch, if_missing: empty }
|
|
134
|
+
list_path: /environmentVariables
|
|
135
|
+
shape: map
|
|
136
|
+
item: { param: name }
|
|
137
|
+
value: { param: value }
|
|
138
|
+
sim:
|
|
139
|
+
provider: aws
|
|
140
|
+
base_path: /aws/amplify
|
|
141
|
+
seed: { amplify: { d1demo: { branches: { pr-42: { environmentVariables: { NODE_ENV: production } } } } } }
|
|
142
|
+
present: /amplify/d1demo/branches/pr-42/environmentVariables/API_URL
|
|
143
|
+
drift:
|
|
144
|
+
changed: { amplify.d1demo.pr-42.API_URL: "https://somewhere-else.example" }
|
|
145
|
+
missing: { amplify.d1demo.pr-42.API_URL: delete }
|
|
146
|
+
live:
|
|
147
|
+
params: { app_id: SPONSON_LIVE_AMPLIFY_APP_ID, branch_name: SPONSON_LIVE_AMPLIFY_BRANCH }
|