@loxtep/sdk 0.9.15 → 0.9.17
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/CHANGELOG.md +45 -0
- package/README.md +4 -4
- package/dist/authoring/types.d.ts +8 -0
- package/dist/authoring/types.d.ts.map +1 -1
- package/dist/cli/commands/deploy-cmd.d.ts.map +1 -1
- package/dist/cli/commands/deploy-cmd.js +30 -15
- package/dist/cli/commands/deploy-cmd.js.map +1 -1
- package/dist/cli/commands/init-cmd.d.ts.map +1 -1
- package/dist/cli/commands/init-cmd.js +54 -24
- package/dist/cli/commands/init-cmd.js.map +1 -1
- package/dist/cli/commands/setup-cmd.d.ts +31 -0
- package/dist/cli/commands/setup-cmd.d.ts.map +1 -0
- package/dist/cli/commands/setup-cmd.js +126 -0
- package/dist/cli/commands/setup-cmd.js.map +1 -0
- package/dist/cli/commands/test-cmd.d.ts +3 -0
- package/dist/cli/commands/test-cmd.d.ts.map +1 -1
- package/dist/cli/commands/test-cmd.js +60 -50
- package/dist/cli/commands/test-cmd.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +7 -3
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/load-workflow-module.d.ts +30 -0
- package/dist/cli/load-workflow-module.d.ts.map +1 -0
- package/dist/cli/load-workflow-module.js +94 -0
- package/dist/cli/load-workflow-module.js.map +1 -0
- package/dist/cli/resolve-package-root.cjs +49 -0
- package/dist/cli/templates-materialize.d.ts +23 -0
- package/dist/cli/templates-materialize.d.ts.map +1 -0
- package/dist/cli/templates-materialize.js +127 -0
- package/dist/cli/templates-materialize.js.map +1 -0
- package/dist/client/bundles-types.d.ts +44 -0
- package/dist/client/bundles-types.d.ts.map +1 -0
- package/dist/client/bundles-types.js +6 -0
- package/dist/client/bundles-types.js.map +1 -0
- package/dist/client/bundles.d.ts +17 -0
- package/dist/client/bundles.d.ts.map +1 -0
- package/dist/client/bundles.js +94 -0
- package/dist/client/bundles.js.map +1 -0
- package/dist/client/data-products.d.ts.map +1 -1
- package/dist/client/data-products.js +24 -2
- package/dist/client/data-products.js.map +1 -1
- package/dist/client/define.d.ts +5 -1
- package/dist/client/define.d.ts.map +1 -1
- package/dist/client/define.js +3 -1
- package/dist/client/define.js.map +1 -1
- package/dist/client/index.d.ts +8 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/loxtep-client.d.ts +5 -2
- package/dist/client/loxtep-client.d.ts.map +1 -1
- package/dist/client/loxtep-client.js +33 -6
- package/dist/client/loxtep-client.js.map +1 -1
- package/dist/client/meaning.d.ts +8 -1
- package/dist/client/meaning.d.ts.map +1 -1
- package/dist/client/meaning.js +4 -1
- package/dist/client/meaning.js.map +1 -1
- package/dist/client/proposals-types.d.ts +68 -0
- package/dist/client/proposals-types.d.ts.map +1 -0
- package/dist/client/proposals-types.js +6 -0
- package/dist/client/proposals-types.js.map +1 -0
- package/dist/client/proposals.d.ts +24 -0
- package/dist/client/proposals.d.ts.map +1 -0
- package/dist/client/proposals.js +140 -0
- package/dist/client/proposals.js.map +1 -0
- package/dist/client/shapes-types.d.ts +102 -0
- package/dist/client/shapes-types.d.ts.map +1 -0
- package/dist/client/shapes-types.js +14 -0
- package/dist/client/shapes-types.js.map +1 -0
- package/dist/client/shapes.d.ts +19 -0
- package/dist/client/shapes.d.ts.map +1 -0
- package/dist/client/shapes.js +110 -0
- package/dist/client/shapes.js.map +1 -0
- package/dist/client/thesaurus-types.d.ts +112 -5
- package/dist/client/thesaurus-types.d.ts.map +1 -1
- package/dist/client/thesaurus-types.js +2 -1
- package/dist/client/thesaurus-types.js.map +1 -1
- package/dist/client/thesaurus.d.ts +17 -3
- package/dist/client/thesaurus.d.ts.map +1 -1
- package/dist/client/thesaurus.js +120 -14
- package/dist/client/thesaurus.js.map +1 -1
- package/dist/config/platform-request-url.d.ts.map +1 -1
- package/dist/config/platform-request-url.js +5 -1
- package/dist/config/platform-request-url.js.map +1 -1
- package/dist/rstreams/leo-runtime.d.ts +6 -1
- package/dist/rstreams/leo-runtime.d.ts.map +1 -1
- package/dist/rstreams/leo-runtime.js +15 -2
- package/dist/rstreams/leo-runtime.js.map +1 -1
- package/docs/code-first-cli.md +28 -12
- package/docs/sdk-mcp-mapping.md +70 -3
- package/package.json +6 -4
- package/templates/shopify-orders/AGENTS.md +35 -0
- package/templates/shopify-orders/README.md +50 -0
- package/templates/shopify-orders/events/order-created.json +17 -0
- package/templates/shopify-orders/package.json +11 -0
- package/templates/shopify-orders/skills/shopify-orders.yaml +29 -0
- package/templates/shopify-orders/tsconfig.json +14 -0
- package/templates/shopify-orders/workflows/orders-enricher.ts +31 -0
package/docs/sdk-mcp-mapping.md
CHANGED
|
@@ -14,8 +14,8 @@ deprecation aliases.
|
|
|
14
14
|
| `loxtep_connect` | `client.connect` | `.connectors.*`, `.templates.*` |
|
|
15
15
|
| `loxtep_workspace` | `client.workspace` | `.projects.*`, `.instances.*` (`list`/`get`/`create`; **`get_stream_config` is REST/CLI only** — not an MCP op). `.versions` (REST pending); planned MCP `get_project_workspace_status` → `ProjectWorkspaceStatus` ([docs](./project-workspace-status.md)) |
|
|
16
16
|
| `loxtep_build` | `client.build` | `.workflows.*`, `.triggers.*`, `.data_products.*`, `.targets.*`, deploy writes, `.get_writer({ bot_id, queue })` escape hatch |
|
|
17
|
-
| `loxtep_define` | `client.define` | `.schemas
|
|
18
|
-
| `loxtep_meaning` | `client.meaning` | `.thesaurus.*`, `.ontology.*`, `.packs.*`, `.semantic
|
|
17
|
+
| `loxtep_define` | `client.define` | `.schemas.*` (data-product), `.shapes.*` (domain canonical shapes), `.quality.*`, `.standards.*`, `.data_contracts.*`, `.domains.*` |
|
|
18
|
+
| `loxtep_meaning` | `client.meaning` | `.thesaurus.*`, `.ontology.*`, `.packs.*`, `.semantic.*`, `.proposals.*`, `.bundles.import` |
|
|
19
19
|
| `loxtep_review` | `client.review` | `.approvals.*`, `.improvements.*`, `.cdlc.*` (get/transition/propagate/lineage/deps + `list_review_queue`); `.mining.*` (`run_mining_pass`, `list_candidates`, `act_on_candidate`). CLI: `loxtep cdlc …`, `loxtep candidates list|act` |
|
|
20
20
|
| `loxtep_query` | `client.query` | `.catalog.*`, `.discovery.*`, `.query()`, `.list_tables()`, `.search()` |
|
|
21
21
|
| `loxtep_observe` | `client.observe` | `.status()`, `.stream_config()`, queue `.open_reader` / `.open_writer`, `.list_deployments()`, `.get_deployment()`, trust signals |
|
|
@@ -58,9 +58,31 @@ Bus physical names (`LeoCron`, `LeoS3`, …): Node `loxtep instances stream-conf
|
|
|
58
58
|
or `client.workspace.instances.get_stream_config(id)` (Python same method). Not
|
|
59
59
|
MCP `list_instances` or `get_sdk_config`.
|
|
60
60
|
|
|
61
|
+
## Meaning: thesaurus / vocabulary (Phase 2)
|
|
62
|
+
|
|
63
|
+
MCP `loxtep_meaning` thesaurus ops map to `client.meaning.thesaurus`:
|
|
64
|
+
|
|
65
|
+
| MCP operation | SDK | REST |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| `list_terms` | `client.meaning.thesaurus.list_terms()` | `GET /graph/organizations/{org}/thesaurus` |
|
|
68
|
+
| `get_term` | `.get_term(term_id)` | `GET …/thesaurus/{term_id}` |
|
|
69
|
+
| `create_term` | `.create_term({ canonical_key, aliases, … })` | `POST …/thesaurus` |
|
|
70
|
+
| `update_term` | `.update_term(term_id, { … })` | `PUT …/thesaurus/{term_id}` |
|
|
71
|
+
| `delete_term` | `.delete_term(term_id)` | `DELETE …/thesaurus/{term_id}` |
|
|
72
|
+
| `sync_vocabulary` | `.sync_vocabulary({ domain, terms, mode, dry_run? })` | `POST …/thesaurus/sync` |
|
|
73
|
+
| `create_enterprise_override` | `.create_enterprise_override({ canonical_key, enterprise_definition, divergence_reason, … })` | `POST …/thesaurus` (`is_override: true`) |
|
|
74
|
+
| `resolve_canonical_key` | `.resolve_canonical_key(key_or_alias)` | client-side over `list_terms` |
|
|
75
|
+
| append synonym (SDK) | `.append_synonym(canonical_key, alias_path, …)` | `POST …/thesaurus/synonyms` |
|
|
76
|
+
|
|
77
|
+
MCP-only (no SDK yet): `list_enterprise_overrides`, `resolve_semantic_gap`,
|
|
78
|
+
namespace-mapping CRUD (`register_namespace_mapping`, `list_namespace_mappings`,
|
|
79
|
+
`get_namespace_mapping`).
|
|
80
|
+
|
|
61
81
|
## Meaning: ontology concepts (LOX-1241)
|
|
62
82
|
|
|
63
|
-
MCP `loxtep_meaning` ontology ops map to `client.meaning.ontology
|
|
83
|
+
MCP `loxtep_meaning` ontology ops map to `client.meaning.ontology`.
|
|
84
|
+
`node_type` is a **lowercase** enum: `entity` \| `microservice` \| `taxonomy` \|
|
|
85
|
+
`pattern` \| `custom` (not `Entity`).
|
|
64
86
|
|
|
65
87
|
| MCP operation | SDK |
|
|
66
88
|
| --- | --- |
|
|
@@ -74,6 +96,10 @@ MCP `loxtep_meaning` ontology ops map to `client.meaning.ontology`:
|
|
|
74
96
|
|
|
75
97
|
REST: `/graph/organizations/{org}/ontology/concepts` and `…/relationships`.
|
|
76
98
|
|
|
99
|
+
Ontology concepts are **graph types and relationships** between them. Defining
|
|
100
|
+
**meaning** for agents/stewards is primarily **terms** (`thesaurus`) + **shapes**
|
|
101
|
+
(`client.define.shapes`).
|
|
102
|
+
|
|
77
103
|
## Meaning: vocabulary packs (LOX-1242)
|
|
78
104
|
|
|
79
105
|
These ops live under MCP **`loxtep_meaning`** / semantic-layer (not `loxtep_define`).
|
|
@@ -117,6 +143,47 @@ Notes:
|
|
|
117
143
|
- SDK calls the semantic-layer MS REST routes directly. MCP-only enrichments (empty-search / completeness `metadata.activation_state` from pack activation) are not duplicated — use `client.meaning.packs.get_activation_status()` when needed.
|
|
118
144
|
- Pack lifecycle remains under `client.meaning.packs` (see vocabulary packs section above).
|
|
119
145
|
|
|
146
|
+
## Meaning: semantic proposals (Phase 2)
|
|
147
|
+
|
|
148
|
+
Agent review of the same inbox Meaning shows. Batch helpers fan out to the
|
|
149
|
+
single-id PUT (no dedicated batch REST).
|
|
150
|
+
|
|
151
|
+
| Concern | SDK | REST |
|
|
152
|
+
| --- | --- | --- |
|
|
153
|
+
| list proposals | `client.meaning.proposals.list({ disposition?, proposal_type?, … })` | `GET /semantic-layer/semantic-proposals` |
|
|
154
|
+
| accept | `.accept(semantic_proposal_id, { resolution_note? })` | `PUT …/semantic-proposals/{id}` `disposition: accepted` |
|
|
155
|
+
| reject | `.reject(semantic_proposal_id, { resolution_note? })` | `PUT …` `disposition: rejected` |
|
|
156
|
+
| batch accept / reject | `.accept_batch` / `.reject_batch` | N× PUT |
|
|
157
|
+
|
|
158
|
+
## Meaning: semantic bundles (Phase 2)
|
|
159
|
+
|
|
160
|
+
| MCP operation | SDK | REST |
|
|
161
|
+
| --- | --- | --- |
|
|
162
|
+
| `import_semantic_bundle` | `client.meaning.bundles.import({ bundle, dry_run? })` | `POST /semantic-layer/bundles/import` |
|
|
163
|
+
|
|
164
|
+
Phase 0 error contract: result always includes `skipped_count` and `errors`.
|
|
165
|
+
When skips/errors exist (or HTTP 207/422 with a parseable body), the SDK sets
|
|
166
|
+
`partial: true` and still returns the result instead of dropping error detail.
|
|
167
|
+
MCP-only sibling: `export_semantic_bundle` (no SDK yet).
|
|
168
|
+
|
|
169
|
+
## Define: domain shapes (Phase 2)
|
|
170
|
+
|
|
171
|
+
Domain / org **canonical shapes** (`domain_schemas`) — distinct from
|
|
172
|
+
`client.define.schemas` (data-product schema versions on `/dataproducts`).
|
|
173
|
+
|
|
174
|
+
| MCP operation | SDK | REST |
|
|
175
|
+
| --- | --- | --- |
|
|
176
|
+
| `create_schema` | `client.define.shapes.create({ name, format, … })` | `POST /semantic-layer/schemas` |
|
|
177
|
+
| `list_schemas` | `.list({ domain_id?, format?, search? })` | `GET /semantic-layer/schemas` |
|
|
178
|
+
| `get_schema` (by `schema_id`) | `.get(schema_id)` | `GET /semantic-layer/schemas/{schema_id}` |
|
|
179
|
+
| `apply_schema` | `.apply({ schema_id, data_product_id, schema_version_id? })` | `POST …/schemas/{schema_id}/applications` |
|
|
180
|
+
| `patch_schema` (align) | `.align({ schema_id, aligned_to_concept_uri })` | `PUT …/schemas/{schema_id}` |
|
|
181
|
+
|
|
182
|
+
MCP-only (no SDK yet): `update_schema`, `delete_schema`, `list_schema_versions`,
|
|
183
|
+
`unapply_schema`, `list_schema_applications`, `add_schema_version`,
|
|
184
|
+
`get_schema_impact`, `install_schema_pack`. Data-product PII tagging stays on
|
|
185
|
+
`client.define.schemas.tag_pii_fields`.
|
|
186
|
+
|
|
120
187
|
## Review: CDLC + context mining (LOX-1244…1247)
|
|
121
188
|
|
|
122
189
|
MCP `loxtep_review` CDLC / mining ops map to `client.review.cdlc` and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loxtep/sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.17",
|
|
4
4
|
"description": "Loxtep SDK for Node.js — the Enterprise Context Layer: data products, workflows, projects, queues, and machine-usable context for AI",
|
|
5
5
|
"author": "Loxtep <engineering@loxtep.io>",
|
|
6
6
|
"homepage": "https://loxtep.io",
|
|
@@ -34,17 +34,19 @@
|
|
|
34
34
|
"dist",
|
|
35
35
|
"docs",
|
|
36
36
|
"schemas",
|
|
37
|
+
"templates",
|
|
37
38
|
"CHANGELOG.md"
|
|
38
39
|
],
|
|
39
40
|
"scripts": {
|
|
40
|
-
"build": "tsc && mkdir -p dist/lib/entity-json-schemas && cp src/lib/entity-json-schemas/ajv-loader.cjs dist/lib/entity-json-schemas/ajv-loader.cjs",
|
|
41
|
+
"build": "tsc && mkdir -p dist/lib/entity-json-schemas && cp src/lib/entity-json-schemas/ajv-loader.cjs dist/lib/entity-json-schemas/ajv-loader.cjs && cp src/cli/resolve-package-root.cjs dist/cli/resolve-package-root.cjs",
|
|
41
42
|
"prepublishOnly": "npm run build",
|
|
42
43
|
"test": "jest --config jest.config.cjs",
|
|
43
44
|
"lint": "eslint src --ext .ts",
|
|
44
45
|
"sync:entity-schemas": "node scripts/sync-entity-schemas.mjs",
|
|
45
46
|
"generate:api-types": "tsx scripts/generate-api-types.ts",
|
|
46
47
|
"docs": "typedoc",
|
|
47
|
-
"test:e2e:cli": "bash scripts/cli-e2e.sh"
|
|
48
|
+
"test:e2e:cli": "bash scripts/cli-e2e.sh",
|
|
49
|
+
"test:e2e:try-it": "bash scripts/try-it-onboarding-e2e.sh"
|
|
48
50
|
},
|
|
49
51
|
"publishConfig": {
|
|
50
52
|
"access": "public",
|
|
@@ -89,6 +91,7 @@
|
|
|
89
91
|
"ajv-formats": "^3.0.1",
|
|
90
92
|
"js-yaml": "^4.3.0",
|
|
91
93
|
"leo-sdk": "7.1.21",
|
|
94
|
+
"tsx": "^4.22.0",
|
|
92
95
|
"zod": "^4.4.3"
|
|
93
96
|
},
|
|
94
97
|
"devDependencies": {
|
|
@@ -97,7 +100,6 @@
|
|
|
97
100
|
"fast-check": "^4.8.0",
|
|
98
101
|
"jest": "^30.4.2",
|
|
99
102
|
"ts-jest": "^29.4.9",
|
|
100
|
-
"tsx": "^4.22.0",
|
|
101
103
|
"typedoc": "^0.28.19",
|
|
102
104
|
"typescript": "^6.0.3",
|
|
103
105
|
"zod-to-ts": "^2.0.0"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# AGENTS.md — shopify-orders
|
|
2
|
+
|
|
3
|
+
This project was scaffolded from the `shopify-orders` template (Try it sample).
|
|
4
|
+
|
|
5
|
+
## MCP tools
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{ "mcpServers": { "loxtep": { "url": "https://mcp.loxtep.io/ai/mcp/stream" } } }
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Dev MCP host: `https://mcpdev.loxtep.io/ai/mcp/stream`.
|
|
12
|
+
|
|
13
|
+
## Lifecycle
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
loxtep login
|
|
17
|
+
loxtep attach --instance <non-prod-instance-id>
|
|
18
|
+
loxtep setup
|
|
19
|
+
loxtep generate
|
|
20
|
+
loxtep test orders-enricher --event ./events/order-created.json
|
|
21
|
+
loxtep deploy
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`loxtep test` runs the handler locally with **live** instance I/O. Approve
|
|
25
|
+
`dataProducts.write` when prompted.
|
|
26
|
+
|
|
27
|
+
## SDK methods
|
|
28
|
+
|
|
29
|
+
- `LoxtepClient.fromWorkspace()` — configure from `.loxtep/project.json`
|
|
30
|
+
- `defineDataWorkflow({ name, triggers, handler, requireApproval })`
|
|
31
|
+
- `workspace.dataProducts.*` — typed constants after `loxtep generate`
|
|
32
|
+
|
|
33
|
+
## Skill scope
|
|
34
|
+
|
|
35
|
+
Default skill: `.loxtep/skills/shopify-orders.yaml`
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Shopify orders sample (`shopify-orders`)
|
|
2
|
+
|
|
3
|
+
Minimal code-first Loxtep workspace used by [Try it](https://loxtep.io/try-it).
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
| Requirement | Notes |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| **Node.js 22+** | `node --version` |
|
|
10
|
+
| **Loxtep account** | [app.loxtep.io](https://app.loxtep.io) |
|
|
11
|
+
| **Auth** | `loxtep login` (writes `./.loxtep/credentials.json`) |
|
|
12
|
+
| **Instance** | Non-production preferred — `loxtep instances list` then `loxtep attach` |
|
|
13
|
+
| **Domain** | Org must have at least one domain (create in UI if none) |
|
|
14
|
+
|
|
15
|
+
`loxtep test` executes your handler **locally with live instance I/O** (stream writes).
|
|
16
|
+
It is not an offline simulator. Sample writes require terminal approval
|
|
17
|
+
(`requireApproval: ['dataProducts.write']`).
|
|
18
|
+
|
|
19
|
+
## Lifecycle (empty directory → deploy)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
mkdir shopify-orders-demo && cd shopify-orders-demo
|
|
23
|
+
npm init -y
|
|
24
|
+
npm install @loxtep/sdk@^0.9.16
|
|
25
|
+
npx loxtep login
|
|
26
|
+
npx loxtep init --template shopify-orders
|
|
27
|
+
npx loxtep attach --instance <non-prod-instance-id>
|
|
28
|
+
npx loxtep setup # provisions orders_raw + orders_enriched (idempotent)
|
|
29
|
+
npx loxtep generate
|
|
30
|
+
npx loxtep test orders-enricher --event ./events/order-created.json
|
|
31
|
+
# Approve dataProducts.write when prompted (y)
|
|
32
|
+
npx loxtep deploy
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Re-running `setup` is safe: existing data products are reused.
|
|
36
|
+
|
|
37
|
+
## What this template scaffolds
|
|
38
|
+
|
|
39
|
+
| Path | Purpose |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `workflows/orders-enricher.ts` | Sample module (webhook → enrich → write) |
|
|
42
|
+
| `events/order-created.json` | Fixture for `loxtep test` |
|
|
43
|
+
| `AGENTS.md` / `.loxtep/skills/` | Agent + skill scope |
|
|
44
|
+
| `package.json` / `tsconfig.json` | Node 22 + typed workflows |
|
|
45
|
+
|
|
46
|
+
## Approval / failure behavior
|
|
47
|
+
|
|
48
|
+
- Reject or timeout on a guarded write → operation skipped, **nonzero exit**
|
|
49
|
+
- Handler or toolbox errors → recorded in the action trace, **nonzero exit**
|
|
50
|
+
- Success → exit 0 and a trace with `handler.start` → `dataProducts.write` → `handler.complete`
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "gid://shopify/Order/5678901234",
|
|
3
|
+
"name": "#1001",
|
|
4
|
+
"email": "customer@example.com",
|
|
5
|
+
"created_at": "2026-09-22T12:00:00Z",
|
|
6
|
+
"currency": "USD",
|
|
7
|
+
"total_price": "129.99",
|
|
8
|
+
"financial_status": "paid",
|
|
9
|
+
"line_items": [
|
|
10
|
+
{
|
|
11
|
+
"id": 1,
|
|
12
|
+
"title": "Sample Widget",
|
|
13
|
+
"quantity": 1,
|
|
14
|
+
"price": "129.99"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Default skill for the shopify-orders template.
|
|
2
|
+
# Scoped to the sample resources provisioned by `loxtep setup`.
|
|
3
|
+
name: shopify-orders
|
|
4
|
+
description: Shopify orders enricher sample — orders_raw ingest and orders_enriched write target
|
|
5
|
+
scope:
|
|
6
|
+
# workflows left empty until after first `loxtep deploy` of orders-enricher
|
|
7
|
+
# (generate validates skill refs against the live workspace).
|
|
8
|
+
data_products:
|
|
9
|
+
- orders_raw
|
|
10
|
+
- orders_enriched
|
|
11
|
+
connectors: []
|
|
12
|
+
workflows: []
|
|
13
|
+
domains: []
|
|
14
|
+
queues: []
|
|
15
|
+
permissions:
|
|
16
|
+
data_products:
|
|
17
|
+
- read
|
|
18
|
+
- write
|
|
19
|
+
connectors:
|
|
20
|
+
- read
|
|
21
|
+
workflows:
|
|
22
|
+
- read
|
|
23
|
+
- write
|
|
24
|
+
- create
|
|
25
|
+
domains:
|
|
26
|
+
- read
|
|
27
|
+
queues:
|
|
28
|
+
- read
|
|
29
|
+
- write
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"types": ["node"]
|
|
12
|
+
},
|
|
13
|
+
"include": ["workflows/**/*.ts", ".loxtep/generated/**/*.ts"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sample: enrich an inbound Shopify order and write it to `orders_enriched`.
|
|
3
|
+
*
|
|
4
|
+
* Prerequisites (see README / `loxtep setup`):
|
|
5
|
+
* - attached non-production instance
|
|
6
|
+
* - `orders_enriched` data product provisioned and deployed
|
|
7
|
+
* - `loxtep generate` so `.loxtep/generated` exists
|
|
8
|
+
*
|
|
9
|
+
* `loxtep test` runs this handler locally against the attached instance
|
|
10
|
+
* (live stream I/O — not an offline simulation). `dataProducts.write` is
|
|
11
|
+
* gated by `requireApproval` so sample writes cannot silently hit the bus.
|
|
12
|
+
*/
|
|
13
|
+
import { defineDataWorkflow, on } from '@loxtep/sdk';
|
|
14
|
+
import { workspace } from '../.loxtep/generated/index.js';
|
|
15
|
+
|
|
16
|
+
export default defineDataWorkflow({
|
|
17
|
+
name: 'orders-enricher',
|
|
18
|
+
// Webhook trigger avoids depending on a friendly observe queue name.
|
|
19
|
+
// After `loxtep setup`, you can switch to on.queueEvent(workspace.queues.*)
|
|
20
|
+
// once a matching queue appears in `loxtep generate` output.
|
|
21
|
+
triggers: [on.webhook('/shopify/orders')],
|
|
22
|
+
requireApproval: ['dataProducts.write'],
|
|
23
|
+
async handler(ctx, event) {
|
|
24
|
+
const order = (event ?? {}) as Record<string, unknown>;
|
|
25
|
+
await ctx.toolbox.dataProducts.write(workspace.dataProducts.orders_enriched, {
|
|
26
|
+
...order,
|
|
27
|
+
enriched_at: new Date().toISOString(),
|
|
28
|
+
source: 'orders-enricher',
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
});
|