@stackables/bridge-graphql 0.0.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +59 -0
  2. package/build/bridge-core/src/ExecutionTree.d.ts +213 -0
  3. package/build/bridge-core/src/ExecutionTree.d.ts.map +1 -0
  4. package/build/bridge-core/src/ExecutionTree.js +1323 -0
  5. package/build/bridge-core/src/execute-bridge.d.ts +69 -0
  6. package/build/bridge-core/src/execute-bridge.d.ts.map +1 -0
  7. package/build/bridge-core/src/execute-bridge.js +52 -0
  8. package/build/bridge-core/src/index.d.ts +18 -0
  9. package/build/bridge-core/src/index.d.ts.map +1 -0
  10. package/build/bridge-core/src/index.js +20 -0
  11. package/build/bridge-core/src/merge-documents.d.ts +25 -0
  12. package/build/bridge-core/src/merge-documents.d.ts.map +1 -0
  13. package/build/bridge-core/src/merge-documents.js +91 -0
  14. package/build/bridge-core/src/tools/index.d.ts +2 -0
  15. package/build/bridge-core/src/tools/index.d.ts.map +1 -0
  16. package/build/bridge-core/src/tools/index.js +1 -0
  17. package/build/bridge-core/src/tools/internal.d.ts +71 -0
  18. package/build/bridge-core/src/tools/internal.d.ts.map +1 -0
  19. package/build/bridge-core/src/tools/internal.js +59 -0
  20. package/build/bridge-core/src/types.d.ts +349 -0
  21. package/build/bridge-core/src/types.d.ts.map +1 -0
  22. package/build/bridge-core/src/types.js +3 -0
  23. package/build/bridge-core/src/utils.d.ts +9 -0
  24. package/build/bridge-core/src/utils.d.ts.map +1 -0
  25. package/build/bridge-core/src/utils.js +23 -0
  26. package/build/bridge-core/src/version-check.d.ts +64 -0
  27. package/build/bridge-core/src/version-check.d.ts.map +1 -0
  28. package/build/bridge-core/src/version-check.js +205 -0
  29. package/build/{bridge-transform.d.ts → bridge-graphql/src/bridge-transform.d.ts} +16 -8
  30. package/build/bridge-graphql/src/bridge-transform.d.ts.map +1 -0
  31. package/build/{bridge-transform.js → bridge-graphql/src/bridge-transform.js} +17 -15
  32. package/build/{index.d.ts → bridge-graphql/src/index.d.ts} +1 -1
  33. package/build/bridge-graphql/src/index.d.ts.map +1 -0
  34. package/build/bridge-stdlib/src/index.d.ts +34 -0
  35. package/build/bridge-stdlib/src/index.d.ts.map +1 -0
  36. package/build/bridge-stdlib/src/index.js +40 -0
  37. package/build/bridge-stdlib/src/tools/arrays.d.ts +28 -0
  38. package/build/bridge-stdlib/src/tools/arrays.d.ts.map +1 -0
  39. package/build/bridge-stdlib/src/tools/arrays.js +50 -0
  40. package/build/bridge-stdlib/src/tools/audit.d.ts +36 -0
  41. package/build/bridge-stdlib/src/tools/audit.d.ts.map +1 -0
  42. package/build/bridge-stdlib/src/tools/audit.js +39 -0
  43. package/build/bridge-stdlib/src/tools/http-call.d.ts +35 -0
  44. package/build/bridge-stdlib/src/tools/http-call.d.ts.map +1 -0
  45. package/build/bridge-stdlib/src/tools/http-call.js +118 -0
  46. package/build/bridge-stdlib/src/tools/strings.d.ts +13 -0
  47. package/build/bridge-stdlib/src/tools/strings.d.ts.map +1 -0
  48. package/build/bridge-stdlib/src/tools/strings.js +12 -0
  49. package/build/bridge-types/src/index.d.ts +63 -0
  50. package/build/bridge-types/src/index.d.ts.map +1 -0
  51. package/build/bridge-types/src/index.js +8 -0
  52. package/package.json +3 -3
  53. package/build/bridge-transform.d.ts.map +0 -1
  54. package/build/index.d.ts.map +0 -1
  55. /package/build/{index.js → bridge-graphql/src/index.js} +0 -0
@@ -1,12 +1,20 @@
1
1
  import { type GraphQLSchema } from "graphql";
2
2
  import { type Logger, type ToolTrace, type TraceLevel } from "@stackables/bridge-core";
3
- import type { Instruction, ToolMap } from "@stackables/bridge-core";
3
+ import type { BridgeDocument, ToolMap } from "@stackables/bridge-core";
4
4
  export type { Logger };
5
5
  export type BridgeOptions = {
6
- /** Tool functions available to the engine.
7
- * Supports namespaced nesting: `{ myNamespace: { myTool } }`.
8
- * The built-in `std` namespace and `httpCall` are always included;
9
- * user tools are merged on top (shallow). */
6
+ /**
7
+ * Tool functions available to the engine.
8
+ * Supports namespaced nesting: `{ myNamespace: { myTool } }`.
9
+ * The built-in `std` namespace is always included; user tools are
10
+ * merged on top (shallow).
11
+ *
12
+ * To provide a specific version of std (e.g. when bridge files
13
+ * target an older major), use a versioned namespace key:
14
+ * ```ts
15
+ * tools: { "std@1.5": oldStdNamespace }
16
+ * ```
17
+ */
10
18
  tools?: ToolMap;
11
19
  /** Optional function to reshape/restrict the GQL context before it reaches bridge files.
12
20
  * By default the full context is exposed via `with context`. */
@@ -24,9 +32,9 @@ export type BridgeOptions = {
24
32
  */
25
33
  logger?: Logger;
26
34
  };
27
- /** Instructions can be a static array or a function that selects per-request */
28
- export type InstructionSource = Instruction[] | ((context: any) => Instruction[]);
29
- export declare function bridgeTransform(schema: GraphQLSchema, instructions: InstructionSource, options?: BridgeOptions): GraphQLSchema;
35
+ /** Document can be a static BridgeDocument or a function that selects per-request */
36
+ export type DocumentSource = BridgeDocument | ((context: any) => BridgeDocument);
37
+ export declare function bridgeTransform(schema: GraphQLSchema, document: DocumentSource, options?: BridgeOptions): GraphQLSchema;
30
38
  /**
31
39
  * Read traces that were collected during the current request.
32
40
  * Pass the GraphQL context object; returns an empty array when tracing is
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-transform.d.ts","sourceRoot":"","sources":["../../../src/bridge-transform.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AAKjC,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGvE,YAAY,EAAE,MAAM,EAAE,CAAC;AAUvB,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;qEACiE;IACjE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtD;;;6DAGyD;IACzD,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qFAAqF;AACrF,MAAM,MAAM,cAAc,GACtB,cAAc,GACd,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,cAAc,CAAC,CAAC;AAEvC,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,aAAa,GACtB,aAAa,CAmIf;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,GAAG,GAAG,SAAS,EAAE,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB;wBAER;QAAE,IAAI,EAAE;YAAE,YAAY,EAAE,GAAG,CAAA;SAAE,CAAA;KAAE;8CAK5C;YACD,MAAM,EAAE,GAAG,CAAC;YACZ,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;SAC7B;;EAeR"}
@@ -1,7 +1,7 @@
1
1
  import { MapperKind, mapSchema } from "@graphql-tools/utils";
2
2
  import { GraphQLList, GraphQLNonNull, defaultFieldResolver, } from "graphql";
3
- import { ExecutionTree, TraceCollector, } from "@stackables/bridge-core";
4
- import { std } from "@stackables/bridge-stdlib";
3
+ import { ExecutionTree, TraceCollector, resolveStd, checkHandleVersions, } from "@stackables/bridge-core";
4
+ import { std as bundledStd, STD_VERSION as BUNDLED_STD_VERSION, } from "@stackables/bridge-stdlib";
5
5
  import { SELF_MODULE } from "@stackables/bridge-core";
6
6
  const noop = () => { };
7
7
  const defaultLogger = {
@@ -10,8 +10,8 @@ const defaultLogger = {
10
10
  warn: noop,
11
11
  error: noop,
12
12
  };
13
- export function bridgeTransform(schema, instructions, options) {
14
- const userTools = options?.tools;
13
+ export function bridgeTransform(schema, document, options) {
14
+ const userTools = options?.tools ?? {};
15
15
  const contextMapper = options?.contextMapper;
16
16
  const traceLevel = options?.trace ?? "off";
17
17
  const logger = options?.logger ?? defaultLogger;
@@ -33,13 +33,21 @@ export function bridgeTransform(schema, instructions, options) {
33
33
  resolve: async function (source, args, context, info) {
34
34
  // Start execution tree at query/mutation root
35
35
  if (!source && !info.path.prev) {
36
- const activeInstructions = typeof instructions === "function"
37
- ? instructions(context)
38
- : instructions;
36
+ const activeDoc = typeof document === "function" ? document(context) : document;
37
+ // Resolve which std to use: bundled, or a versioned namespace from tools
38
+ const { namespace: activeStd, version: activeStdVersion } = resolveStd(activeDoc.version, bundledStd, BUNDLED_STD_VERSION, userTools);
39
+ // std is always included; user tools merge on top (shallow)
40
+ // internal tools are injected automatically by ExecutionTree
41
+ const allTools = {
42
+ std: activeStd,
43
+ ...userTools,
44
+ };
45
+ // Verify all @version-tagged handles can be satisfied
46
+ checkHandleVersions(activeDoc.instructions, allTools, activeStdVersion);
39
47
  // Only intercept fields that have a matching bridge instruction.
40
48
  // Fields without one fall through to their original resolver,
41
49
  // allowing hand-coded resolvers to coexist with bridge-powered ones.
42
- const hasBridge = activeInstructions.some((i) => i.kind === "bridge" &&
50
+ const hasBridge = activeDoc.instructions.some((i) => i.kind === "bridge" &&
43
51
  i.type === typeName &&
44
52
  i.field === fieldName);
45
53
  if (!hasBridge) {
@@ -48,13 +56,7 @@ export function bridgeTransform(schema, instructions, options) {
48
56
  const bridgeContext = contextMapper
49
57
  ? contextMapper(context)
50
58
  : (context ?? {});
51
- // std is always included; user tools merge on top (shallow)
52
- // internal tools are injected automatically by ExecutionTree
53
- const allTools = {
54
- std,
55
- ...(userTools ?? {}),
56
- };
57
- source = new ExecutionTree(trunk, activeInstructions, allTools, bridgeContext);
59
+ source = new ExecutionTree(trunk, activeDoc, allTools, bridgeContext);
58
60
  source.logger = logger;
59
61
  if (traceLevel !== "off") {
60
62
  source.tracer = new TraceCollector(traceLevel);
@@ -7,5 +7,5 @@
7
7
  * Peer dependencies: `graphql`, `@graphql-tools/utils`.
8
8
  */
9
9
  export { bridgeTransform, getBridgeTraces, useBridgeTracing, } from "./bridge-transform.ts";
10
- export type { BridgeOptions, InstructionSource } from "./bridge-transform.ts";
10
+ export type { BridgeOptions, DocumentSource } from "./bridge-transform.ts";
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,eAAe,EACf,eAAe,EACf,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @stackables/bridge-stdlib — Bridge standard library tools.
3
+ *
4
+ * Contains the `std` namespace tools (httpCall, string helpers, array helpers,
5
+ * audit) that ship with Bridge. Referenced in `.bridge` files as
6
+ * `std.httpCall`, `std.str.toUpperCase`, etc.
7
+ *
8
+ * Separated from core so it can be versioned independently.
9
+ */
10
+ import { audit } from "./tools/audit.ts";
11
+ import * as arrays from "./tools/arrays.ts";
12
+ import * as strings from "./tools/strings.ts";
13
+ /**
14
+ * Standard library version.
15
+ *
16
+ * The bridge `version X.Y` header declares the minimum compatible std version.
17
+ * At runtime the engine compares this constant against the bridge's declared
18
+ * version to verify compatibility (same major, equal-or-higher minor).
19
+ */
20
+ export declare const STD_VERSION = "1.5.0";
21
+ export declare const std: {
22
+ readonly str: typeof strings;
23
+ readonly arr: typeof arrays;
24
+ readonly audit: typeof audit;
25
+ readonly httpCall: import("@stackables/bridge-types").ToolCallFn;
26
+ };
27
+ /**
28
+ * All known built-in tool names as "namespace.tool" strings.
29
+ *
30
+ * Useful for LSP/IDE autocomplete and diagnostics.
31
+ */
32
+ export declare const builtinToolNames: readonly string[];
33
+ export { createHttpCall } from "./tools/http-call.ts";
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../bridge-stdlib/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAE9C;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,UAAU,CAAC;AASnC,eAAO,MAAM,GAAG;;;;;CAKN,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAE7C,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @stackables/bridge-stdlib — Bridge standard library tools.
3
+ *
4
+ * Contains the `std` namespace tools (httpCall, string helpers, array helpers,
5
+ * audit) that ship with Bridge. Referenced in `.bridge` files as
6
+ * `std.httpCall`, `std.str.toUpperCase`, etc.
7
+ *
8
+ * Separated from core so it can be versioned independently.
9
+ */
10
+ import { audit } from "./tools/audit.js";
11
+ import { createHttpCall } from "./tools/http-call.js";
12
+ import * as arrays from "./tools/arrays.js";
13
+ import * as strings from "./tools/strings.js";
14
+ /**
15
+ * Standard library version.
16
+ *
17
+ * The bridge `version X.Y` header declares the minimum compatible std version.
18
+ * At runtime the engine compares this constant against the bridge's declared
19
+ * version to verify compatibility (same major, equal-or-higher minor).
20
+ */
21
+ export const STD_VERSION = "1.5.0";
22
+ /**
23
+ * Standard built-in tools — available under the `std` namespace.
24
+ *
25
+ * Referenced in `.bridge` files as `std.str.toUpperCase`, `std.arr.first`, etc.
26
+ */
27
+ const httpCallFn = createHttpCall();
28
+ export const std = {
29
+ str: strings,
30
+ arr: arrays,
31
+ audit,
32
+ httpCall: httpCallFn,
33
+ };
34
+ /**
35
+ * All known built-in tool names as "namespace.tool" strings.
36
+ *
37
+ * Useful for LSP/IDE autocomplete and diagnostics.
38
+ */
39
+ export const builtinToolNames = Object.keys(std).map((k) => `std.${k}`);
40
+ export { createHttpCall } from "./tools/http-call.js";
@@ -0,0 +1,28 @@
1
+ export declare function filter(opts: {
2
+ in: any[];
3
+ [key: string]: any;
4
+ }): any[];
5
+ export declare function find(opts: {
6
+ in: any[];
7
+ [key: string]: any;
8
+ }): any;
9
+ /**
10
+ * Returns the first element of the array in `opts.in`.
11
+ *
12
+ * By default silently returns `undefined` for empty arrays.
13
+ * Set `opts.strict` to `true` (or the string "true") to throw when
14
+ * the array is empty or contains more than one element.
15
+ */
16
+ export declare function first(opts: {
17
+ in: any[];
18
+ strict?: boolean | string;
19
+ }): any;
20
+ /**
21
+ * Wraps a single value in an array.
22
+ *
23
+ * If `opts.in` is already an array it is returned as-is.
24
+ */
25
+ export declare function toArray(opts: {
26
+ in: any;
27
+ }): any[];
28
+ //# sourceMappingURL=arrays.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrays.d.ts","sourceRoot":"","sources":["../../../../../bridge-stdlib/src/tools/arrays.ts"],"names":[],"mappings":"AAAA,wBAAgB,MAAM,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,GAAG,EAAE,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,SAU7D;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,GAAG,EAAE,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,OAU3D;AAED;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,GAAG,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;CAAE,OAgBnE;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,SAExC"}
@@ -0,0 +1,50 @@
1
+ export function filter(opts) {
2
+ const { in: arr, ...criteria } = opts;
3
+ return arr.filter((obj) => {
4
+ for (const [key, value] of Object.entries(criteria)) {
5
+ if (obj[key] !== value) {
6
+ return false;
7
+ }
8
+ }
9
+ return true;
10
+ });
11
+ }
12
+ export function find(opts) {
13
+ const { in: arr, ...criteria } = opts;
14
+ return arr.find((obj) => {
15
+ for (const [key, value] of Object.entries(criteria)) {
16
+ if (obj[key] !== value) {
17
+ return false;
18
+ }
19
+ }
20
+ return true;
21
+ });
22
+ }
23
+ /**
24
+ * Returns the first element of the array in `opts.in`.
25
+ *
26
+ * By default silently returns `undefined` for empty arrays.
27
+ * Set `opts.strict` to `true` (or the string "true") to throw when
28
+ * the array is empty or contains more than one element.
29
+ */
30
+ export function first(opts) {
31
+ const arr = opts.in;
32
+ const strict = opts.strict === true || opts.strict === "true";
33
+ if (strict) {
34
+ if (!Array.isArray(arr) || arr.length === 0) {
35
+ throw new Error("pickFirst: expected a non-empty array");
36
+ }
37
+ if (arr.length > 1) {
38
+ throw new Error(`pickFirst: expected exactly one element but got ${arr.length}`);
39
+ }
40
+ }
41
+ return Array.isArray(arr) ? arr[0] : undefined;
42
+ }
43
+ /**
44
+ * Wraps a single value in an array.
45
+ *
46
+ * If `opts.in` is already an array it is returned as-is.
47
+ */
48
+ export function toArray(opts) {
49
+ return Array.isArray(opts.in) ? opts.in : [opts.in];
50
+ }
@@ -0,0 +1,36 @@
1
+ import type { ToolContext } from "@stackables/bridge-types";
2
+ /**
3
+ * Built-in audit tool — logs all inputs via the engine logger.
4
+ *
5
+ * Designed for use with `force` — wire any number of inputs,
6
+ * force the handle, and every key-value pair is logged.
7
+ *
8
+ * The logger comes from the engine's `ToolContext` (configured via
9
+ * `BridgeOptions.logger`). When no logger is configured the engine's
10
+ * default no-op logger applies — nothing is logged.
11
+ *
12
+ * Structured logging style: data object first, message tag last.
13
+ *
14
+ * The log level defaults to `info` but can be overridden via `level` input:
15
+ * ```bridge
16
+ * audit.level = "warn"
17
+ * ```
18
+ *
19
+ * ```bridge
20
+ * bridge Mutation.createOrder {
21
+ * with std.audit as audit
22
+ * with orderApi as api
23
+ * with input as i
24
+ * with output as o
25
+ *
26
+ * api.userId <- i.userId
27
+ * audit.action = "createOrder"
28
+ * audit.userId <- i.userId
29
+ * audit.orderId <- api.id
30
+ * force audit
31
+ * o.id <- api.id
32
+ * }
33
+ * ```
34
+ */
35
+ export declare function audit(input: Record<string, any>, context?: ToolContext): Record<string, any>;
36
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../../../bridge-stdlib/src/tools/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,WAAW,uBAKtE"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Built-in audit tool — logs all inputs via the engine logger.
3
+ *
4
+ * Designed for use with `force` — wire any number of inputs,
5
+ * force the handle, and every key-value pair is logged.
6
+ *
7
+ * The logger comes from the engine's `ToolContext` (configured via
8
+ * `BridgeOptions.logger`). When no logger is configured the engine's
9
+ * default no-op logger applies — nothing is logged.
10
+ *
11
+ * Structured logging style: data object first, message tag last.
12
+ *
13
+ * The log level defaults to `info` but can be overridden via `level` input:
14
+ * ```bridge
15
+ * audit.level = "warn"
16
+ * ```
17
+ *
18
+ * ```bridge
19
+ * bridge Mutation.createOrder {
20
+ * with std.audit as audit
21
+ * with orderApi as api
22
+ * with input as i
23
+ * with output as o
24
+ *
25
+ * api.userId <- i.userId
26
+ * audit.action = "createOrder"
27
+ * audit.userId <- i.userId
28
+ * audit.orderId <- api.id
29
+ * force audit
30
+ * o.id <- api.id
31
+ * }
32
+ * ```
33
+ */
34
+ export function audit(input, context) {
35
+ const { level = "info", ...data } = input;
36
+ const log = context?.logger?.[level];
37
+ log?.(data, "[bridge:audit]");
38
+ return input;
39
+ }
@@ -0,0 +1,35 @@
1
+ import type { CacheStore, ToolCallFn } from "@stackables/bridge-types";
2
+ /**
3
+ * Parse TTL (in seconds) from HTTP response headers.
4
+ *
5
+ * Priority: `Cache-Control: s-maxage` > `Cache-Control: max-age` > `Expires`.
6
+ * Returns 0 if the response is uncacheable (no-store, no-cache, or no headers).
7
+ */
8
+ declare function parseCacheTTL(response: Response): number;
9
+ /**
10
+ * Create an httpCall tool function — the built-in REST API tool.
11
+ *
12
+ * Receives a fully-built input object from the engine and makes an HTTP call.
13
+ * The engine resolves all wires (from tool definition + bridge wires) before calling.
14
+ *
15
+ * Expected input shape:
16
+ * { baseUrl, method?, path?, headers?, cache?, ...shorthandFields }
17
+ *
18
+ * Routing rules:
19
+ * - GET: shorthand fields → query string parameters
20
+ * - POST/PUT/PATCH/DELETE: shorthand fields → JSON body
21
+ * - `headers` object passed as HTTP headers
22
+ * - `baseUrl` + `path` concatenated for the URL
23
+ *
24
+ * Cache modes:
25
+ * - `cache = "auto"` (default) — respect HTTP Cache-Control / Expires headers
26
+ * - `cache = 0` — disable caching entirely
27
+ * - `cache = <seconds>` — explicit TTL override, ignores response headers
28
+ *
29
+ * @param fetchFn - Fetch implementation (override for testing)
30
+ * @param cacheStore - Pluggable cache store (default: in-memory LRU, 1024 entries)
31
+ */
32
+ export declare function createHttpCall(fetchFn?: typeof fetch, cacheStore?: CacheStore): ToolCallFn;
33
+ /** Exported for testing. */
34
+ export { parseCacheTTL };
35
+ //# sourceMappingURL=http-call.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-call.d.ts","sourceRoot":"","sources":["../../../../../bridge-stdlib/src/tools/http-call.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAgBvE;;;;;GAKG;AACH,iBAAS,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAejD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAC5B,OAAO,GAAE,OAAO,KAAwB,EACxC,UAAU,GAAE,UAAgC,GAC3C,UAAU,CAkEZ;AAED,4BAA4B;AAC5B,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { LRUCache } from "lru-cache";
2
+ /** Default in-memory LRU cache with per-entry TTL. */
3
+ function createMemoryCache(maxEntries = 1024) {
4
+ const lru = new LRUCache({ max: maxEntries });
5
+ return {
6
+ get(key) {
7
+ return lru.get(key);
8
+ },
9
+ set(key, value, ttlSeconds) {
10
+ if (ttlSeconds <= 0)
11
+ return;
12
+ lru.set(key, value, { ttl: ttlSeconds * 1000 });
13
+ },
14
+ };
15
+ }
16
+ /**
17
+ * Parse TTL (in seconds) from HTTP response headers.
18
+ *
19
+ * Priority: `Cache-Control: s-maxage` > `Cache-Control: max-age` > `Expires`.
20
+ * Returns 0 if the response is uncacheable (no-store, no-cache, or no headers).
21
+ */
22
+ function parseCacheTTL(response) {
23
+ const cc = response.headers.get("cache-control");
24
+ if (cc) {
25
+ if (/\bno-store\b/i.test(cc) || /\bno-cache\b/i.test(cc))
26
+ return 0;
27
+ const sMax = cc.match(/\bs-maxage\s*=\s*(\d+)\b/i);
28
+ if (sMax)
29
+ return Number(sMax[1]);
30
+ const max = cc.match(/\bmax-age\s*=\s*(\d+)\b/i);
31
+ if (max)
32
+ return Number(max[1]);
33
+ }
34
+ const expires = response.headers.get("expires");
35
+ if (expires) {
36
+ const delta = Math.floor((new Date(expires).getTime() - Date.now()) / 1000);
37
+ return delta > 0 ? delta : 0;
38
+ }
39
+ return 0;
40
+ }
41
+ /**
42
+ * Create an httpCall tool function — the built-in REST API tool.
43
+ *
44
+ * Receives a fully-built input object from the engine and makes an HTTP call.
45
+ * The engine resolves all wires (from tool definition + bridge wires) before calling.
46
+ *
47
+ * Expected input shape:
48
+ * { baseUrl, method?, path?, headers?, cache?, ...shorthandFields }
49
+ *
50
+ * Routing rules:
51
+ * - GET: shorthand fields → query string parameters
52
+ * - POST/PUT/PATCH/DELETE: shorthand fields → JSON body
53
+ * - `headers` object passed as HTTP headers
54
+ * - `baseUrl` + `path` concatenated for the URL
55
+ *
56
+ * Cache modes:
57
+ * - `cache = "auto"` (default) — respect HTTP Cache-Control / Expires headers
58
+ * - `cache = 0` — disable caching entirely
59
+ * - `cache = <seconds>` — explicit TTL override, ignores response headers
60
+ *
61
+ * @param fetchFn - Fetch implementation (override for testing)
62
+ * @param cacheStore - Pluggable cache store (default: in-memory LRU, 1024 entries)
63
+ */
64
+ export function createHttpCall(fetchFn = globalThis.fetch, cacheStore = createMemoryCache()) {
65
+ return async (input) => {
66
+ const { baseUrl = "", method = "GET", path = "", headers: inputHeaders = {}, cache: cacheMode = "auto", ...rest } = input;
67
+ // Build URL
68
+ const url = new URL(baseUrl + path);
69
+ // Collect headers
70
+ const headers = {};
71
+ for (const [key, value] of Object.entries(inputHeaders)) {
72
+ if (value != null)
73
+ headers[key] = String(value);
74
+ }
75
+ // GET: shorthand fields → query string
76
+ if (method === "GET") {
77
+ for (const [key, value] of Object.entries(rest)) {
78
+ if (value != null) {
79
+ url.searchParams.set(key, String(value));
80
+ }
81
+ }
82
+ }
83
+ // Non-GET: shorthand fields → JSON body
84
+ let body;
85
+ if (method !== "GET") {
86
+ const bodyObj = {};
87
+ for (const [key, value] of Object.entries(rest)) {
88
+ if (value != null)
89
+ bodyObj[key] = value;
90
+ }
91
+ if (Object.keys(bodyObj).length > 0) {
92
+ body = JSON.stringify(bodyObj);
93
+ headers["Content-Type"] ??= "application/json";
94
+ }
95
+ }
96
+ // cache = 0 → no caching at all
97
+ const mode = String(cacheMode);
98
+ if (mode === "0") {
99
+ const response = await fetchFn(url.toString(), { method, headers, body });
100
+ return response.json();
101
+ }
102
+ const cacheKey = method + " " + url.toString() + (body ?? "");
103
+ // Check cache before fetching
104
+ const cached = await cacheStore.get(cacheKey);
105
+ if (cached !== undefined)
106
+ return cached;
107
+ const response = await fetchFn(url.toString(), { method, headers, body });
108
+ const data = (await response.json());
109
+ // Determine TTL
110
+ const ttl = mode === "auto" ? parseCacheTTL(response) : Number(mode);
111
+ if (ttl > 0) {
112
+ await cacheStore.set(cacheKey, data, ttl);
113
+ }
114
+ return data;
115
+ };
116
+ }
117
+ /** Exported for testing. */
118
+ export { parseCacheTTL };
@@ -0,0 +1,13 @@
1
+ export declare function toLowerCase(opts: {
2
+ in: string;
3
+ }): string;
4
+ export declare function toUpperCase(opts: {
5
+ in: string;
6
+ }): string;
7
+ export declare function trim(opts: {
8
+ in: string;
9
+ }): string;
10
+ export declare function length(opts: {
11
+ in: string;
12
+ }): number;
13
+ //# sourceMappingURL=strings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../../../../bridge-stdlib/src/tools/strings.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,UAE/C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,UAE/C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,UAExC;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,UAE1C"}
@@ -0,0 +1,12 @@
1
+ export function toLowerCase(opts) {
2
+ return opts.in?.toLowerCase();
3
+ }
4
+ export function toUpperCase(opts) {
5
+ return opts.in?.toUpperCase();
6
+ }
7
+ export function trim(opts) {
8
+ return opts.in?.trim();
9
+ }
10
+ export function length(opts) {
11
+ return opts.in?.length;
12
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @stackables/bridge-types — Shared type definitions for the Bridge ecosystem.
3
+ *
4
+ * These types are used by both bridge-core (engine) and bridge-stdlib (standard
5
+ * library tools). They live in a separate package to break the circular
6
+ * dependency between core and stdlib.
7
+ */
8
+ /**
9
+ * Tool context — runtime services available to every tool call.
10
+ *
11
+ * Passed as the second argument to every ToolCallFn.
12
+ */
13
+ export type ToolContext = {
14
+ /** Structured logger — same instance configured via `BridgeOptions.logger`.
15
+ * Defaults to silent no-ops when no logger is configured. */
16
+ logger: {
17
+ debug?: (...args: any[]) => void;
18
+ info?: (...args: any[]) => void;
19
+ warn?: (...args: any[]) => void;
20
+ error?: (...args: any[]) => void;
21
+ };
22
+ /** External abort signal — allows the caller to cancel execution mid-flight.
23
+ * When aborted, the engine short-circuits before starting new tool calls
24
+ * and propagates the signal to tool implementations via this context field. */
25
+ signal?: AbortSignal;
26
+ };
27
+ /**
28
+ * Tool call function — the signature for registered tool functions.
29
+ *
30
+ * Receives a fully-built nested input object and an optional `ToolContext`
31
+ * providing access to the engine's logger and other services.
32
+ *
33
+ * Example (httpCall):
34
+ * input = { baseUrl: "https://...", method: "GET", path: "/geocode",
35
+ * headers: { apiKey: "..." }, q: "Berlin" }
36
+ */
37
+ export type ToolCallFn = (input: Record<string, any>, context?: ToolContext) => Promise<Record<string, any>>;
38
+ /**
39
+ * Recursive tool map — supports namespaced tools via nesting.
40
+ *
41
+ * Example:
42
+ * { std: { upperCase, lowerCase }, httpCall: createHttpCall(), myCompany: { myTool } }
43
+ *
44
+ * Lookup is dot-separated: "std.str.toUpperCase" → tools.std.str.toUpperCase
45
+ */
46
+ export type ToolMap = {
47
+ [key: string]: ToolCallFn | ((...args: any[]) => any) | ToolMap;
48
+ };
49
+ /**
50
+ * Pluggable cache store for httpCall.
51
+ *
52
+ * Default: in-memory Map with TTL eviction.
53
+ * Override: pass any key-value store (Redis, Memcached, etc.) to `createHttpCall`.
54
+ *
55
+ * ```ts
56
+ * const httpCall = createHttpCall(fetch, myRedisStore);
57
+ * ```
58
+ */
59
+ export type CacheStore = {
60
+ get(key: string): Promise<any | undefined> | any | undefined;
61
+ set(key: string, value: any, ttlSeconds: number): Promise<void> | void;
62
+ };
63
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../bridge-types/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;kEAC8D;IAC9D,MAAM,EAAE;QACN,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;QACjC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;QAChC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;QAChC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;KAClC,CAAC;IACF;;oFAEgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG,CACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,OAAO,CAAC,EAAE,WAAW,KAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC;CACjE,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,GAAG,GAAG,GAAG,SAAS,CAAC;IAC7D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxE,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @stackables/bridge-types — Shared type definitions for the Bridge ecosystem.
3
+ *
4
+ * These types are used by both bridge-core (engine) and bridge-stdlib (standard
5
+ * library tools). They live in a separate package to break the circular
6
+ * dependency between core and stdlib.
7
+ */
8
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackables/bridge-graphql",
3
- "version": "0.0.1",
3
+ "version": "1.0.1",
4
4
  "description": "Bridge GraphQL adapter — wire bridges into a GraphQL schema",
5
5
  "main": "./build/index.js",
6
6
  "type": "module",
@@ -22,8 +22,8 @@
22
22
  },
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
- "@stackables/bridge-stdlib": "0.0.1",
26
- "@stackables/bridge-core": "0.0.1"
25
+ "@stackables/bridge-core": "1.0.1",
26
+ "@stackables/bridge-stdlib": "1.5.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "typescript": "^5.9.3"
@@ -1 +0,0 @@
1
- {"version":3,"file":"bridge-transform.d.ts","sourceRoot":"","sources":["../src/bridge-transform.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGpE,YAAY,EAAE,MAAM,EAAE,CAAC;AAUvB,MAAM,MAAM,aAAa,GAAG;IAC1B;;;kDAG8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;qEACiE;IACjE,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtD;;;6DAGyD;IACzD,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GACzB,WAAW,EAAE,GACb,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,WAAW,EAAE,CAAC,CAAC;AAEtC,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,iBAAiB,EAC/B,OAAO,CAAC,EAAE,aAAa,GACtB,aAAa,CAqHf;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,GAAG,GAAG,SAAS,EAAE,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB;wBAER;QAAE,IAAI,EAAE;YAAE,YAAY,EAAE,GAAG,CAAA;SAAE,CAAA;KAAE;8CAK5C;YACD,MAAM,EAAE,GAAG,CAAC;YACZ,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;SAC7B;;EAeR"}