@oddington/sdk 0.1.14 → 0.1.16

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 CHANGED
@@ -4,6 +4,14 @@ The importable client for Oddington apps, routines and response handlers.
4
4
  Node operations require Node.js 22.12.0 or later. The root import and hosted
5
5
  Data and Files APIs work in browsers. Installing the package grants no authority.
6
6
 
7
+ Hosted Data and shared Files reach OS directly through `/api/data` and `/api/files`.
8
+ Inbox owns workspace-hosted `/api/inbox/check`, `/api/inbox/publish`,
9
+ `/api/inbox/resolve` and `/api/inbox/files`. Request-key recovery and captured
10
+ publication validation are internal behavior of these operations. Retrying the
11
+ same key and content returns the original result; changed content conflicts.
12
+ Existing Inbox-retained files remain separate from shared Files, with their
13
+ original identities, bytes and audience. The SDK exposes no raw-credential API.
14
+
7
15
  ```sh
8
16
  npm install @oddington/sdk
9
17
  ```
package/dist/browser.js CHANGED
@@ -669,6 +669,11 @@ async function executeRoutineDefinition(definition, input, runtime) {
669
669
  let captured = captureRoutineInput(definition, input), { contract, run } = definitions.get(definition), active2 = !0, broken = !1, reports = Promise.resolve(), os2 = Object.freeze({
670
670
  ...runtime,
671
671
  run: freeze({ ...runtime.run }),
672
+ async artifact(input2) {
673
+ if (!active2) throw new Error("Run authority ended");
674
+ if (!runtime.artifact) throw new Error("Run artifact transport unavailable");
675
+ return runtime.artifact(input2);
676
+ },
672
677
  step(id3, ...summary) {
673
678
  if (!active2 || broken || summary.length > 1)
674
679
  return broken = !0, Promise.reject(new AppRoutineContractError("invalid_value"));
@@ -883,12 +888,10 @@ function dataTransportError(status, value) {
883
888
  );
884
889
  }
885
890
 
886
- var AUTH_ORIGIN = "https://auth.oddington.ai";
887
- function oddingtonOrigin(environment = process.env) {
888
- let value = environment.ODDINGTON_OS_ORIGIN ?? AUTH_ORIGIN, url = new URL(value);
889
- if (url.protocol !== "https:" && url.hostname !== "127.0.0.1")
890
- throw new Error("ODDINGTON_OS_ORIGIN must use HTTPS");
891
- return url.origin;
891
+ var installed, ended = !1;
892
+ function routineTransport() {
893
+ if (ended || installed && !installed.isCurrent()) throw new Error("Routine authority ended");
894
+ return installed;
892
895
  }
893
896
 
894
897
  var memberContext;
@@ -954,10 +957,9 @@ function checked(workspace, endpoint, headers) {
954
957
  var data = {
955
958
  repository(repository) {
956
959
  async function send3(input) {
957
- let context2 = await resolveDataContext();
960
+ let context2 = await resolveDataContext(), envelope = { repository, ...input };
961
+ if (checkDataRequestSize(envelope), "local" in context2) return await context2.local("data/query", envelope);
958
962
  try {
959
- let envelope = { repository, ...input };
960
- if (checkDataRequestSize(envelope), "local" in context2) return await context2.local("data/query", envelope);
961
963
  let response2 = await fetch(context2.url, {
962
964
  method: "POST",
963
965
  redirect: "error",
@@ -1026,7 +1028,7 @@ var data = {
1026
1028
  } catch (error) {
1027
1029
  return Promise.reject(error);
1028
1030
  }
1029
- publicationId ??= crypto.randomUUID(), pending = send3({ operation: "changes.publish", ...captured, publicationId }).then((result2) => (confirmed = structuredClone(result2), result2)).catch((error) => {
1031
+ publicationId ??= routineTransport()?.key("data") ?? crypto.randomUUID(), pending = send3({ operation: "changes.publish", ...captured, publicationId }).then((result2) => (confirmed = structuredClone(result2), result2)).catch((error) => {
1030
1032
  throw error instanceof DataOperationError ? new DataOperationError(
1031
1033
  error.code,
1032
1034
  error.retryable,
@@ -1358,7 +1360,7 @@ var files = {
1358
1360
  storage: input.storage,
1359
1361
  csv: input.csv,
1360
1362
  ...blob && input.file.type === "application/pdf" ? { inputMediaType: "application/pdf" } : {},
1361
- requestKey: options?.requestKey === void 0 ? crypto.randomUUID() : options.requestKey
1363
+ requestKey: options?.requestKey === void 0 ? routineTransport()?.key("files") ?? crypto.randomUUID() : options.requestKey
1362
1364
  }, FILE_ORIGINAL_MAX_BYTES);
1363
1365
  if (!context2.local && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
1364
1366
  let header = encodeURIComponent(JSON.stringify(metadata));
@@ -1669,6 +1671,8 @@ async function reportLocalRoutineEffect(value) {
1669
1671
 
1670
1672
  var connections = /* @__PURE__ */ createConnections(async (name, operation2, input) => {
1671
1673
  try {
1674
+ let installed2 = routineTransport();
1675
+ if (installed2) return await installed2.request("airtable", { name, operation: operation2, input: serializable(input) });
1672
1676
  let managed = process.env[MANAGED_CONNECTION_CAPABILITY_ENV];
1673
1677
  if (managed) {
1674
1678
  let client = managedConnections(JSON.parse(managed)).airtable(name);
@@ -2941,7 +2945,7 @@ async function provider(configuration, guard) {
2941
2945
  }
2942
2946
  var auth = /* @__PURE__ */ createBrowserAuth({ provider, failure: (reason) => new BrowserAuthError(reason) });
2943
2947
 
2944
- var identifier = /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/, uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, isReason = (value) => value === "authority_unavailable" || value === "execution_unavailable" || value === "invalid_input", AppRoutineError = class extends Error {
2948
+ var identifier = /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/, uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, isReason = (value) => value === "not_enabled" || value === "authority_unavailable" || value === "execution_unavailable" || value === "invalid_input", AppRoutineError = class extends Error {
2945
2949
  constructor(reason) {
2946
2950
  super(reason);
2947
2951
  this.reason = reason;
@@ -3105,7 +3109,7 @@ async function availability(key) {
3105
3109
  let value = await appResponse(response2, MAX_RESPONSE_BYTES, context2.signal);
3106
3110
  if (!context2.isCurrent() || !value || typeof value != "object" || Array.isArray(value)) return authorityUnavailable();
3107
3111
  let result2 = value;
3108
- return result2.available === !1 && Object.keys(result2).sort().join(",") === "available,reason" && (result2.reason === "authority_unavailable" || result2.reason === "execution_unavailable") ? { available: !1, reason: result2.reason } : result2.available !== !0 || Object.keys(result2).sort().join(",") !== "available,steps" || !Array.isArray(result2.steps) || result2.steps.length < 1 || result2.steps.length > 64 || !result2.steps.every((step) => typeof step == "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/.test(step)) || new Set(result2.steps).size !== result2.steps.length ? authorityUnavailable() : { available: !0, steps: [...result2.steps] };
3112
+ return result2.available === !1 && Object.keys(result2).sort().join(",") === "available,reason" && (result2.reason === "not_enabled" || result2.reason === "authority_unavailable" || result2.reason === "execution_unavailable") ? { available: !1, reason: result2.reason } : result2.available !== !0 || Object.keys(result2).sort().join(",") !== "available,steps" || !Array.isArray(result2.steps) || result2.steps.length < 1 || result2.steps.length > 64 || !result2.steps.every((step) => typeof step == "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/.test(step)) || new Set(result2.steps).size !== result2.steps.length ? authorityUnavailable() : { available: !0, steps: [...result2.steps] };
3109
3113
  } catch {
3110
3114
  return authorityUnavailable();
3111
3115
  }
@@ -3145,13 +3149,20 @@ function validateCsvHints(value) {
3145
3149
  return v;
3146
3150
  }
3147
3151
 
3152
+ var PREPARED_RECORD_INPUT_LIMIT = 64 * 1024 * 1024;
3153
+
3154
+ function routineDataEnvelope(command) {
3155
+ return "preflight" in command ? { operation: "changes.validate", captured: command.preflight } : "apply" in command ? { operation: "changes.publish", captured: command.apply } : { operation: "changes.publish", request: command };
3156
+ }
3157
+
3148
3158
  function routinePublicationClient2(options = {}) {
3149
- let environment = {}, local = void 0, workspace = options.workspace ?? environment.ODDINGTON_ROUTINE_WORKSPACE, capability = options.capability ?? environment.ODDINGTON_ROUTINE_RUN;
3159
+ let environment = {}, installed2 = routineTransport(), local = installed2?.request ?? void 0, workspace = installed2 ? "installed" : options.workspace ?? environment.ODDINGTON_ROUTINE_WORKSPACE, capability = options.capability ?? environment.ODDINGTON_ROUTINE_RUN;
3150
3160
  if (!workspace || !/^[a-z0-9][a-z0-9-]*$/.test(workspace) || capability !== void 0 && !/^[0-9a-f]{64}$/.test(capability))
3151
3161
  throw new Error("A workspace and valid optional routine capability are required");
3152
3162
  let workingRoot = options.workingRoot ?? environment.ODDINGTON_INBOX_WORKING_ROOT ?? void 0, headers = capability ? { "x-oddington-run": capability } : {}, request = options.request ?? (capability ? async (path, init2) => {
3153
- let origin = oddingtonOrigin(), target = new URL(path, `${origin}/`);
3154
- if (target.origin !== origin || !target.pathname.startsWith(`/api/cli/workspaces/${workspace}/inbox/`))
3163
+ if (path === "/api/data") return fetch(`https://${workspace}.oddington.ai/api/data`, { ...init2, redirect: "error" });
3164
+ let origin = `https://${workspace}.oddington.ai`, target = new URL(path, `${origin}/`);
3165
+ if (workspace.length > 63 || ["auth", "www", "api", "os"].includes(workspace) || target.origin !== origin || target.search || target.hash || target.username || target.password || !/^\/api\/inbox\/(check|publish|resolve|files)$/.test(path) || init2?.method !== "POST")
3155
3166
  throw new Error("Invalid routine endpoint");
3156
3167
  return fetch(target, { ...init2, redirect: "error" });
3157
3168
  } : async () => {
@@ -3159,10 +3170,14 @@ function routinePublicationClient2(options = {}) {
3159
3170
  });
3160
3171
  async function send3(operation2, body2) {
3161
3172
  if (local) return await local(operation2, body2);
3162
- let response2 = await request(`/api/cli/workspaces/${workspace}/inbox/${operation2}`, {
3173
+ let writing = operation2 === "records/update", reading = operation2 === "records/read", response2 = await request(writing || reading ? "/api/data" : `/api/inbox/${operation2}`, {
3163
3174
  method: "POST",
3164
- headers: { "content-type": "application/json", ...headers },
3165
- body: JSON.stringify(body2)
3175
+ headers: {
3176
+ "content-type": "application/json",
3177
+ ...headers,
3178
+ ...writing || reading ? { "x-oddington-workspace": workspace, "x-oddington-captured-records": "1" } : {}
3179
+ },
3180
+ body: JSON.stringify(writing ? routineDataEnvelope(validateRoutineRecordWrite(body2)) : reading ? { operation: "records.select", request: validateRecordRead(body2) } : body2)
3166
3181
  }), result2 = await response2.json();
3167
3182
  if (!response2.ok && operation2 === "records/update")
3168
3183
  throw new RoutineRecordWriteError(result2.error ?? "Could not confirm routine preparation", result2.effect ?? "uncertain");
@@ -3186,15 +3201,15 @@ function routinePublicationClient2(options = {}) {
3186
3201
  repository: {
3187
3202
  readRecords,
3188
3203
  async writeRecords(input, options2) {
3189
- if (!capability) throw new Error("A trusted routine launch is required");
3204
+ if (!capability && !installed2) throw new Error("A trusted routine launch is required");
3190
3205
  return await send3("records/update", validateRoutineRecordWrite({ input, requestKey: options2?.requestKey }));
3191
3206
  },
3192
3207
  async updateRecords(input, options2) {
3193
- if (!capability) throw new Error("A trusted routine launch is required");
3208
+ if (!capability && !installed2) throw new Error("A trusted routine launch is required");
3194
3209
  return await send3("records/update", validateRoutineRecordWrite({ input: validateRecordUpdate(input), requestKey: options2?.requestKey }));
3195
3210
  },
3196
3211
  async deleteRecords(input, options2) {
3197
- if (!capability) throw new Error("A trusted routine launch is required");
3212
+ if (!capability && !installed2) throw new Error("A trusted routine launch is required");
3198
3213
  return await send3("records/update", validateRoutineRecordWrite({ input: validateRecordDelete(input), requestKey: options2?.requestKey }));
3199
3214
  }
3200
3215
  },