@oddington/sdk 0.1.35 → 0.1.37

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
@@ -79,6 +79,27 @@ declared `review` handler crosses the Inbox publication seam as `review`; Inbox
79
79
  retains the canonical `invoice-import` routine identity separately, without
80
80
  deploying or executing that handler.
81
81
 
82
+ Microsoft Connection configuration has a separate, optional `access` description.
83
+ It preserves supplied strings, including existing `read` and `read-write` labels,
84
+ and does not grant or restrict Microsoft permissions. Management results omit
85
+ this metadata when absent. Setup and safe inspection are documented in the
86
+ [CLI Connections guide](../../apps/cli/README.md#connections).
87
+
88
+ With `access: { ai: true }`, `os.ai.generateText` returns non-empty `{ text }`.
89
+ `os.ai.generateObject` returns `{ object }` validated against the requested
90
+ `schema`, with its inferred type. An invalid answer throws `RoutineAIError`
91
+ with code `invalid_output`, a clear bounded `detail`, and the original final
92
+ answer as optional `text` for routine-owned recovery. The text is bounded at
93
+ 256 KiB and excluded from the error message and ordinary JSON serialization.
94
+ The routine can inspect it explicitly, apply its own recovery rules, report
95
+ an item failure and continue; it must not cast a rejected answer to the promised
96
+ type. OS does not coerce, drop fields, repair or retry automatically.
97
+
98
+ An AI call failure can be caught and handled without automatically failing the
99
+ Run. Uncaught routine or step exceptions still fail execution, and outstanding
100
+ AI calls drain before completion. The host retains authority, isolation,
101
+ cancellation and byte limits. Local and remote Runs use the same API.
102
+
82
103
  The bounded grammar supports closed objects with required properties, arrays with
83
104
  an explicit `maxItems` from 1 to 64, booleans, strings (at most 4096 code points),
84
105
  finite numbers and safe integers with optional inclusive bounds, and Files.
@@ -489,6 +510,44 @@ revision and URL facts. Distinct objects and custom provider values remain.
489
510
  Helpers need no initialization and perform no I/O, choose no ref, and add no
490
511
  changes. File retention and Data validation/publication remain explicit.
491
512
 
513
+ Microsoft helpers are also exported at the package root, with the corresponding
514
+ `OutlookSourceLocation` and `SharePointSourceLocation` types:
515
+
516
+ ```ts
517
+ const messageLocation = source.location.outlook({
518
+ connection: 'outlook/invoices', message: message.id, url: message.webLink,
519
+ // attachment: attachment.id, // Include for attachment bytes; omit for message MIME.
520
+ });
521
+ const itemLocation = source.location.sharepoint({
522
+ connection: 'sharepoint/operations', site: siteId, drive: driveId, item: item.id,
523
+ version: version.id, path: lastKnownPath, url: item.webUrl,
524
+ });
525
+ ```
526
+
527
+ Construct these only after successful provider reads establish the coordinates
528
+ for the retained bytes, and save them alongside `source.location.os(file)` using
529
+ ordinary Data publication. Request `Prefer: IdType="ImmutableId"` consistently
530
+ when obtaining Outlook message and attachment IDs. These IDs are case-sensitive
531
+ and survive folder moves within the same mailbox, but not archive-mailbox moves
532
+ or export/reimport. Subjects, filenames and `internetMessageId` are not substitutes.
533
+ Omit `attachment` for an exact message MIME File; supply it for an attachment File.
534
+
535
+ For SharePoint, use the saved Graph site ID, the document library's drive ID and
536
+ the file's driveItem ID. Optional `version` is an actual driveItemVersion ID
537
+ established for those bytes, never an eTag or a guessed version. Omit it when no
538
+ such version is established. Names, paths and URLs do not establish identity.
539
+ Optional `path` is last-known context; `url` is the ordinary HTTPS message web
540
+ link or SharePoint webUrl. Never retain temporary download, upload-session or
541
+ copy-monitor URLs, authorization or credentials in Locations.
542
+
543
+ Outlook merge identity is connection/message/attachment, with whole messages
544
+ distinct from attachments. SharePoint identity is connection/site/drive/item/
545
+ version, with absent versions distinct from present ones. Matching observations
546
+ replace path/link context, including removing omitted context; distinct IDs,
547
+ versions and copies remain separate. Incomplete coordinates gain no inferred
548
+ identity. The retained OS File and hash own exact content; external edits do
549
+ not change an existing Source's bytes. These helpers perform no provider I/O.
550
+
492
551
  Read a named repository through the authenticated host context:
493
552
 
494
553
  ```ts
package/dist/browser.js CHANGED
@@ -221,32 +221,45 @@ function jsonData(value, ancestors = /* @__PURE__ */ new Set()) {
221
221
  ancestors.delete(value);
222
222
  }
223
223
  }
224
- function validateRoutineSchemaValue(schema2, value) {
225
- switch (schema2.type) {
226
- case "object":
227
- if (!record(value) || (schema2.required ?? []).some((key) => !owns(value, key)) || Object.keys(value).some((key) => !owns(schema2.properties, key))) return invalidValue();
228
- for (let [key, child] of Object.entries(value)) validateRoutineSchemaValue(schema2.properties[key], child);
229
- return;
230
- case "array":
231
- if (!denseArray(value) || value.length > schema2.maxItems) return invalidValue();
232
- for (let child of value) validateRoutineSchemaValue(schema2.items, child);
233
- return;
234
- case "boolean":
235
- return typeof value != "boolean" ? invalidValue() : void 0;
236
- case "string":
237
- return typeof value != "string" || Array.from(value).length > (schema2.maxLength ?? 4096) ? invalidValue() : void 0;
238
- case "integer":
239
- case "number":
240
- return typeof value != "number" || !(schema2.type === "integer" ? Number.isSafeInteger(value) : Number.isFinite(value)) || schema2.minimum !== void 0 && value < schema2.minimum || schema2.maximum !== void 0 && value > schema2.maximum ? invalidValue() : void 0;
241
- case "file":
242
- try {
243
- jsonData(value);
244
- let file2 = parseFileDescriptor(value);
245
- if (schema2.path !== void 0 && file2.path !== schema2.path) return invalidValue();
246
- } catch {
247
- return invalidValue();
224
+ function validateRoutineSchemaValue(schema2, value, rejected) {
225
+ let type = (value2) => value2 === null ? "null" : Array.isArray(value2) ? "array" : ["object", "boolean", "string", "number"].includes(typeof value2) ? typeof value2 : "other";
226
+ function check(schema3, value2, path) {
227
+ let fail4 = (reason, extra = {}) => (rejected?.({ reason, path: path.length <= 256 ? path : "$", expected: schema3.type, received: type(value2), ...extra }), invalidValue());
228
+ switch (schema3.type) {
229
+ case "object":
230
+ if (!record(value2)) return fail4("wrong_type");
231
+ for (let key of schema3.required ?? []) if (!owns(value2, key)) return fail4("missing_field", {
232
+ path: `${path}.${key}`.length <= 256 ? `${path}.${key}` : "$",
233
+ expected: schema3.properties[key].type,
234
+ received: "missing"
235
+ });
236
+ if (Object.keys(value2).some((key) => !owns(schema3.properties, key))) return fail4("unexpected_field");
237
+ for (let [key, child] of Object.entries(value2)) check(schema3.properties[key], child, `${path}.${key}`);
238
+ return;
239
+ case "array":
240
+ if (!denseArray(value2)) return fail4("wrong_type");
241
+ if (value2.length > schema3.maxItems) return fail4("out_of_bounds", { constraint: "maxItems", limit: schema3.maxItems });
242
+ value2.forEach((child, index) => check(schema3.items, child, `${path}[${index}]`));
243
+ return;
244
+ case "boolean":
245
+ return typeof value2 != "boolean" ? fail4("wrong_type") : void 0;
246
+ case "string":
247
+ return typeof value2 != "string" ? fail4("wrong_type") : Array.from(value2).length > (schema3.maxLength ?? 4096) ? fail4("out_of_bounds", { constraint: "maxLength", limit: schema3.maxLength ?? 4096 }) : void 0;
248
+ case "integer":
249
+ case "number":
250
+ return typeof value2 != "number" || !(schema3.type === "integer" ? Number.isSafeInteger(value2) : Number.isFinite(value2)) ? fail4("wrong_type") : schema3.minimum !== void 0 && value2 < schema3.minimum ? fail4("out_of_bounds", { constraint: "minimum", limit: schema3.minimum }) : schema3.maximum !== void 0 && value2 > schema3.maximum ? fail4("out_of_bounds", { constraint: "maximum", limit: schema3.maximum }) : void 0;
251
+ case "file": {
252
+ let file2;
253
+ try {
254
+ jsonData(value2), file2 = parseFileDescriptor(value2);
255
+ } catch {
256
+ return fail4("invalid_file");
257
+ }
258
+ if (schema3.path !== void 0 && file2.path !== schema3.path) return fail4("invalid_file");
248
259
  }
260
+ }
249
261
  }
262
+ check(schema2, value, "$");
250
263
  }
251
264
 
252
265
  var InboxContractError = class extends Error {
@@ -695,20 +708,82 @@ function parseRoutineAccess(value) {
695
708
  }
696
709
  }
697
710
 
698
- var ROUTINE_AI_VALUE_BYTES = 256 * 1024, ROUTINE_AI_EVIDENCE_BYTES = 4 * 1024;
711
+ function parseRoutineAIOutputIssue(value) {
712
+ if (!value || typeof value != "object" || Array.isArray(value)) return;
713
+ let v = value;
714
+ if (["invalid_json", "invalid_response", "empty_text"].includes(String(v.reason)))
715
+ return Object.keys(v).join(",") === "reason" ? { reason: v.reason } : void 0;
716
+ if (!(!["missing_field", "unexpected_field", "wrong_type", "out_of_bounds", "invalid_file"].includes(String(v.reason)) || typeof v.path != "string" || v.path.length > 256 || !/^\$(?:\.[a-z][A-Za-z0-9]*|\[(?:0|[1-9][0-9]*)\])*$/.test(v.path) || !["object", "array", "boolean", "string", "integer", "number", "file"].includes(String(v.expected)) || !["missing", "null", "object", "array", "boolean", "string", "number", "other"].includes(String(v.received)) || Object.keys(v).some((key) => !["reason", "path", "expected", "received", "constraint", "limit"].includes(key)))) {
717
+ if (v.reason === "out_of_bounds") {
718
+ if (!["maxLength", "maxItems", "minimum", "maximum"].includes(String(v.constraint)) || typeof v.limit != "number" || !Number.isFinite(v.limit)) return;
719
+ } else if (Object.hasOwn(v, "constraint") || Object.hasOwn(v, "limit")) return;
720
+ return {
721
+ reason: v.reason,
722
+ path: v.path,
723
+ expected: v.expected,
724
+ received: v.received,
725
+ ...v.reason === "out_of_bounds" ? { constraint: v.constraint, limit: v.limit } : {}
726
+ };
727
+ }
728
+ }
729
+ function routineAIOutputMessage(issue) {
730
+ if (issue.reason === "invalid_json") return "AI replied, but its answer could not be read as JSON.";
731
+ if (issue.reason === "invalid_response") return "AI returned a response OS could not read.";
732
+ if (issue.reason === "empty_text") return "AI returned an empty answer.";
733
+ let field = issue.path === "$" ? "response" : issue.path.slice(issue.path.startsWith("$.") ? 2 : 1), expected = {
734
+ object: "an object",
735
+ array: "a list",
736
+ boolean: "true or false",
737
+ string: "text",
738
+ integer: "a whole number",
739
+ number: "a number",
740
+ file: "a File"
741
+ }[issue.expected], received = {
742
+ missing: "a missing field",
743
+ null: "null",
744
+ object: "an object",
745
+ array: "a list",
746
+ boolean: "true or false",
747
+ string: "text",
748
+ number: "a number",
749
+ other: "an unsupported value"
750
+ }[issue.received];
751
+ if (issue.reason === "missing_field") return `AI response is missing a required field.
752
+ ${field}: expected ${expected}; the field was missing.`;
753
+ if (issue.reason === "unexpected_field") return `AI response includes an unexpected field.
754
+ ${field}: only the fields declared by the routine are allowed.`;
755
+ if (issue.reason === "invalid_file") return `AI response contains an invalid File.
756
+ ${field}: expected a valid File matching the routine's requirements.`;
757
+ if (issue.reason === "out_of_bounds") {
758
+ let constraint = {
759
+ maxLength: `at most ${issue.limit} characters`,
760
+ maxItems: `at most ${issue.limit} items`,
761
+ minimum: `a value of at least ${issue.limit}`,
762
+ maximum: `a value of at most ${issue.limit}`
763
+ }[issue.constraint];
764
+ return `AI response is outside a permitted limit.
765
+ ${field}: expected ${constraint}.`;
766
+ }
767
+ return `AI response has the wrong type.
768
+ ${field}: expected ${expected}; received ${received}.`;
769
+ }
770
+
771
+ var ROUTINE_AI_VALUE_BYTES = 256 * 1024, ROUTINE_AI_RESULT_BYTES = 6 * ROUTINE_AI_VALUE_BYTES + 1024, ROUTINE_AI_EVIDENCE_BYTES = 4 * 1024;
699
772
  var RoutineAIError = class extends Error {
700
- constructor(code) {
701
- super(code);
773
+ constructor(code, options = {}) {
774
+ let detail = code === "invalid_output" ? parseRoutineAIOutputIssue(options.detail) : void 0;
775
+ super(detail ? routineAIOutputMessage(detail) : code);
702
776
  this.code = code;
703
- this.name = "RoutineAIError";
777
+ this.name = "RoutineAIError", detail && (this.detail = Object.freeze(detail)), code === "invalid_output" && typeof options.text == "string" && new TextEncoder().encode(options.text).byteLength <= ROUTINE_AI_VALUE_BYTES && Object.defineProperty(this, "text", { value: options.text });
704
778
  }
705
779
  code;
780
+ detail;
706
781
  };
707
- function capture(value, invalid9, oversized) {
782
+ function capture(value, invalid9, oversized, limit = ROUTINE_AI_VALUE_BYTES) {
708
783
  try {
709
784
  assertRoutineJson(value);
710
785
  let encoded = JSON.stringify(value);
711
- if (new TextEncoder().encode(encoded).byteLength > ROUTINE_AI_VALUE_BYTES) throw new RoutineAIError(oversized);
786
+ if (new TextEncoder().encode(encoded).byteLength > limit) throw new RoutineAIError(oversized);
712
787
  return freezeRoutineMetadata(JSON.parse(encoded));
713
788
  } catch (error) {
714
789
  throw error instanceof RoutineAIError ? error : new RoutineAIError(invalid9);
@@ -727,19 +802,47 @@ function parseRoutineAIRequest(value) {
727
802
  }
728
803
  }
729
804
  function parseRoutineAIResult(request2, value) {
730
- let v = capture(value, "invalid_output", "output_too_large");
805
+ let v;
731
806
  try {
732
- if (request2.kind === "generateText") {
733
- if (assertRoutineFields(v, ["text"]), typeof v.text != "string" || !v.text.trim()) throw new Error();
734
- return freezeRoutineMetadata({ text: v.text });
735
- } else {
736
- if (assertRoutineFields(v, ["object"]), !Object.hasOwn(v, "object")) throw new Error();
737
- return validateRoutineSchemaValue(request2.schema, v.object), freezeRoutineMetadata({ object: v.object });
807
+ if (v = capture(
808
+ value,
809
+ "invalid_output",
810
+ "output_too_large",
811
+ request2.kind === "generateText" ? ROUTINE_AI_RESULT_BYTES : ROUTINE_AI_VALUE_BYTES
812
+ ), assertRoutineFields(v, request2.kind === "generateText" ? ["text"] : ["object"]), request2.kind === "generateText") {
813
+ if (typeof v.text != "string") throw new Error();
814
+ return acceptText(request2, v.text);
738
815
  }
816
+ if (!Object.hasOwn(v, "object")) throw new Error();
817
+ } catch (error) {
818
+ throw error instanceof RoutineAIError ? error : new RoutineAIError("invalid_output", { detail: { reason: "invalid_response" } });
819
+ }
820
+ return validateObject(request2.schema, v.object), freezeRoutineMetadata({ object: v.object });
821
+ }
822
+ function validateObject(schema2, object5, text5) {
823
+ let detail = { reason: "invalid_response" };
824
+ try {
825
+ validateRoutineSchemaValue(schema2, object5, (issue) => {
826
+ detail = issue;
827
+ });
739
828
  } catch {
740
- throw new RoutineAIError("invalid_output");
829
+ throw new RoutineAIError("invalid_output", { ...text5 === void 0 ? {} : { text: text5 }, detail });
741
830
  }
742
831
  }
832
+ function acceptText(request2, text5) {
833
+ if (new TextEncoder().encode(text5).byteLength > ROUTINE_AI_VALUE_BYTES) throw new RoutineAIError("output_too_large");
834
+ if (request2.kind === "generateText") {
835
+ if (!text5.trim()) throw new RoutineAIError("invalid_output", { text: text5, detail: { reason: "empty_text" } });
836
+ return freezeRoutineMetadata({ text: text5 });
837
+ }
838
+ let object5;
839
+ try {
840
+ object5 = JSON.parse(text5);
841
+ } catch {
842
+ throw new RoutineAIError("invalid_output", { text: text5, detail: { reason: "invalid_json" } });
843
+ }
844
+ return validateObject(request2.schema, object5, text5), capture({ object: object5 }, "invalid_output", "output_too_large");
845
+ }
743
846
 
744
847
  var LIMIT = 256 * 1024, invalid3 = () => {
745
848
  throw new AppRoutineContractError("invalid_value");
@@ -865,7 +968,7 @@ function captureRoutineInput(definition, input) {
865
968
  return capture2(contract.input, input === void 0 && Object.hasOwn(contract, "inputDefault") ? contract.inputDefault : input);
866
969
  }
867
970
  async function executeRoutineDefinition(definition, input, runtime) {
868
- let captured = captureRoutineInput(definition, input), { contract, steps, run } = definitions.get(definition), active2 = !0, accepting = !0, broken = !1, work = Promise.resolve(), aiFailure, aiWork = /* @__PURE__ */ new Set(), generate = (kind, value) => {
971
+ let captured = captureRoutineInput(definition, input), { contract, steps, run } = definitions.get(definition), active2 = !0, accepting = !0, broken = !1, work = Promise.resolve(), aiWork = /* @__PURE__ */ new Set(), generate = (kind, value) => {
869
972
  let operation2 = (async () => {
870
973
  if (!active2 || broken || contract.access.ai !== !0) throw new RoutineAIError("access_denied");
871
974
  if (!runtime.ai) throw new RoutineAIError("capability_unavailable");
@@ -884,9 +987,7 @@ async function executeRoutineDefinition(definition, input, runtime) {
884
987
  if (!active2 || broken) throw new RoutineAIError("access_denied");
885
988
  return parseRoutineAIResult(request2, result3);
886
989
  })();
887
- return aiWork.add(operation2), operation2.then(() => aiWork.delete(operation2), (error) => {
888
- aiFailure ??= error, broken = !0, aiWork.delete(operation2);
889
- }), operation2;
990
+ return aiWork.add(operation2), operation2.then(() => aiWork.delete(operation2), () => aiWork.delete(operation2)), operation2;
890
991
  }, called = /* @__PURE__ */ new Set(), reached = /* @__PURE__ */ new Set(), guarded = (value, receiver) => typeof value == "function" ? (...args) => {
891
992
  if (!active2 || broken) throw new Error("Run authority ended");
892
993
  return guarded(Reflect.apply(value, receiver, args));
@@ -950,7 +1051,7 @@ async function executeRoutineDefinition(definition, input, runtime) {
950
1051
  for (accepting = !1, await work; aiWork.size; ) await Promise.allSettled([...aiWork]);
951
1052
  active2 = !1;
952
1053
  for (let step of contract.steps) reached.has(step.id) || await runtime.step(step.id, { status: "skipped" });
953
- if (broken) throw failure ?? aiFailure ?? new AppRoutineContractError("invalid_value");
1054
+ if (broken) throw failure ?? new AppRoutineContractError("invalid_value");
954
1055
  if (contract.result !== void 0) return capture2(contract.result, result2);
955
1056
  if (result2 !== void 0) return invalid3();
956
1057
  }
@@ -1859,6 +1960,37 @@ var files = {
1859
1960
  function validDropboxRootPath(value) {
1860
1961
  return typeof value == "string" && value.length <= 2048 && value.startsWith("/") && !/[\\\x00-\x1f\x7f]/.test(value) && value.slice(1).split("/").every((segment) => segment.length > 0 && segment.trim() === segment && segment !== "." && segment !== "..");
1861
1962
  }
1963
+ function validMicrosoftId(value) {
1964
+ return typeof value == "string" && /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(value);
1965
+ }
1966
+ function validMicrosoftMailbox(value) {
1967
+ return typeof value == "string" && value.length <= 254 && /^[^\s@/?#\\\x00-\x1f\x7f]+@[^\s@/?#\\\x00-\x1f\x7f]+\.[^\s@/?#\\\x00-\x1f\x7f]+$/.test(value);
1968
+ }
1969
+ function sharePointHost(value) {
1970
+ return /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.sharepoint\.com$/.test(value);
1971
+ }
1972
+ function canonicalSharePointSiteUrl(value) {
1973
+ if (!(typeof value != "string" || value.length > 2048 || /[\s\\?#\x00-\x1f\x7f]/.test(value) || !/^https:\/\/[^/:@]+(?:\/|$)/i.test(value)))
1974
+ try {
1975
+ let url = new URL(value);
1976
+ if (url.protocol !== "https:" || !sharePointHost(url.hostname) || url.username || url.password || url.port) return;
1977
+ let rawPath = value.replace(/^https:\/\/[^/]+/i, "") || "/", path = rawPath.endsWith("/") ? rawPath.slice(0, -1) : rawPath, segments = path.slice(1).split("/");
1978
+ if (path && segments.some((segment) => !segment)) return;
1979
+ let encoded = path ? segments.map((segment) => {
1980
+ let decoded = decodeURIComponent(segment);
1981
+ if (decoded === "." || decoded === ".." || /[/%\\?#\x00-\x1f\x7f]/.test(decoded)) throw new Error();
1982
+ return encodeURIComponent(decoded);
1983
+ }).join("/") : "", canonical = `https://${url.hostname}/${encoded}`;
1984
+ return canonical.length <= 2048 ? canonical : void 0;
1985
+ } catch {
1986
+ return;
1987
+ }
1988
+ }
1989
+ function validSharePointSiteId(value, siteUrl) {
1990
+ if (typeof value != "string" || value.length > 512) return !1;
1991
+ let [host, collection, site, extra] = value.split(",");
1992
+ return extra === void 0 && host === new URL(siteUrl).hostname && validMicrosoftId(collection) && validMicrosoftId(site);
1993
+ }
1862
1994
  function validGoogleScopes(value) {
1863
1995
  return Array.isArray(value) && value.length > 0 && value.length <= 32 && value.every((scope) => typeof scope == "string" && scope.length <= 256 && /^(https:\/\/www\.googleapis\.com\/auth\/[A-Za-z0-9._-]+|https:\/\/mail\.google\.com\/|openid|email|profile)$/.test(scope)) && new Set(value).size === value.length;
1864
1996
  }
@@ -1869,13 +2001,32 @@ function validDropboxFileScopes(value) {
1869
2001
 
1870
2002
  var ROUTINE_CONNECTION_CREDENTIALS_ENV = "OS_ROUTINE_CONNECTION_CREDENTIALS";
1871
2003
  function parseRoutineConnectionNames(value) {
1872
- if (!Array.isArray(value) || value.some((name2) => typeof name2 != "string" || !/^(gmail|airtable|dropbox)\/[a-z0-9][a-z0-9-]{0,62}$/.test(name2)) || new Set(value).size !== value.length)
2004
+ if (!Array.isArray(value) || value.some((name2) => typeof name2 != "string" || !/^(gmail|airtable|dropbox|outlook|sharepoint)\/[a-z0-9][a-z0-9-]{0,62}$/.test(name2)) || new Set(value).size !== value.length)
1873
2005
  throw new Error("Invalid routine connections");
1874
2006
  return value;
1875
2007
  }
1876
2008
  var connectionUuid = (v) => typeof v == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(v);
1877
2009
  function runtimeConnection(lease) {
1878
2010
  switch (lease.provider) {
2011
+ case "outlook":
2012
+ return {
2013
+ id: `outlook/${lease.name}`,
2014
+ provider: lease.provider,
2015
+ name: lease.name,
2016
+ mailboxEmail: lease.mailboxEmail,
2017
+ accessToken: lease.accessToken,
2018
+ expiresAt: lease.expiresAt
2019
+ };
2020
+ case "sharepoint":
2021
+ return {
2022
+ id: `sharepoint/${lease.name}`,
2023
+ provider: lease.provider,
2024
+ name: lease.name,
2025
+ siteId: lease.siteId,
2026
+ siteUrl: lease.siteUrl,
2027
+ accessToken: lease.accessToken,
2028
+ expiresAt: lease.expiresAt
2029
+ };
1879
2030
  case "gmail":
1880
2031
  return {
1881
2032
  id: `gmail/${lease.name}`,
@@ -1913,6 +2064,11 @@ function parseConnectionLease(raw, now = Date.now()) {
1913
2064
  let v = raw;
1914
2065
  if (!v || typeof v != "object" || Array.isArray(v) || !connectionUuid(v.connectionId) || !connectionUuid(v.runId) || typeof v.name != "string" || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(v.name) || typeof v.accessToken != "string" || !/^[A-Za-z0-9._~+/-]{1,8192}={0,2}$/.test(v.accessToken))
1915
2066
  throw new Error("Invalid connection credential");
2067
+ if (v.provider === "outlook" || v.provider === "sharepoint") {
2068
+ if (!(v.provider === "outlook" ? Object.keys(v).sort().join(",") === "accessToken,connectionId,expiresAt,mailboxEmail,name,provider,runId" && validMicrosoftMailbox(v.mailboxEmail) : Object.keys(v).sort().join(",") === "accessToken,connectionId,expiresAt,name,provider,runId,siteId,siteUrl" && typeof v.siteUrl == "string" && canonicalSharePointSiteUrl(v.siteUrl) === v.siteUrl && validSharePointSiteId(v.siteId, v.siteUrl)) || typeof v.expiresAt != "string" || !Number.isFinite(Date.parse(v.expiresAt)) || Date.parse(v.expiresAt) <= now + 6e4 || Date.parse(v.expiresAt) > now + 36e5)
2069
+ throw new Error("Invalid connection credential");
2070
+ return v;
2071
+ }
1916
2072
  if (v.provider === "gmail") {
1917
2073
  if (Object.keys(v).sort().join(",") !== "accessToken,accountEmail,connectionId,expiresAt,name,provider,runId,scopes" || typeof v.accountEmail != "string" || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.accountEmail) || !validGoogleScopes(v.scopes) || typeof v.expiresAt != "string" || !Number.isFinite(Date.parse(v.expiresAt)) || Date.parse(v.expiresAt) <= now + 6e4 || Date.parse(v.expiresAt) > now + 36e5)
1918
2074
  throw new Error("Invalid connection credential");
@@ -2180,7 +2336,17 @@ var connections = /* @__PURE__ */ runtimeConnections();
2180
2336
  var LOCAL_ROUTINE_VALUE_BYTES = 256 * 1024;
2181
2337
 
2182
2338
  function locationIdentity(location) {
2183
- let coordinates = location.provider === "os" ? [location.file] : location.provider === "gmail" ? [location.connection, location.message, location.attachment] : location.provider === "dropbox" ? [location.connection, location.file] : void 0;
2339
+ let coordinates = location.provider === "os" ? [location.file] : location.provider === "gmail" ? [location.connection, location.message, location.attachment] : location.provider === "dropbox" ? [location.connection, location.file] : location.provider === "outlook" ? [
2340
+ location.connection,
2341
+ location.message,
2342
+ ...location.attachment === void 0 ? [] : [location.attachment]
2343
+ ] : location.provider === "sharepoint" ? [
2344
+ location.connection,
2345
+ location.site,
2346
+ location.drive,
2347
+ location.item,
2348
+ ...location.version === void 0 ? [] : [location.version]
2349
+ ] : void 0;
2184
2350
  if (coordinates?.every((value) => typeof value == "string" && value.length > 0))
2185
2351
  return JSON.stringify([location.provider, ...coordinates]);
2186
2352
  }
@@ -2219,6 +2385,27 @@ var source = {
2219
2385
  ...input.path === void 0 ? {} : { path: input.path },
2220
2386
  ...input.url === void 0 ? {} : { url: input.url }
2221
2387
  };
2388
+ },
2389
+ outlook(input) {
2390
+ return {
2391
+ provider: "outlook",
2392
+ connection: input.connection,
2393
+ message: input.message,
2394
+ ...input.attachment === void 0 ? {} : { attachment: input.attachment },
2395
+ ...input.url === void 0 ? {} : { url: input.url }
2396
+ };
2397
+ },
2398
+ sharepoint(input) {
2399
+ return {
2400
+ provider: "sharepoint",
2401
+ connection: input.connection,
2402
+ site: input.site,
2403
+ drive: input.drive,
2404
+ item: input.item,
2405
+ ...input.version === void 0 ? {} : { version: input.version },
2406
+ ...input.path === void 0 ? {} : { path: input.path },
2407
+ ...input.url === void 0 ? {} : { url: input.url }
2408
+ };
2222
2409
  }
2223
2410
  },
2224
2411
  locations: {
@@ -4016,6 +4203,7 @@ export {
4016
4203
  FileOperationError,
4017
4204
  InboxContractError,
4018
4205
  InboxOperationError,
4206
+ RoutineAIError,
4019
4207
  app,
4020
4208
  asksBlock,
4021
4209
  auth,