@granular-software/sdk 0.4.16 → 0.4.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/dist/index.d.mts +80 -2
- package/dist/index.d.ts +80 -2
- package/dist/index.js +174 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +174 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -11815,6 +11815,70 @@ var Environment = class extends Session {
|
|
|
11815
11815
|
await this._runGraphql(mutation.query, mutation.label);
|
|
11816
11816
|
}
|
|
11817
11817
|
}
|
|
11818
|
+
async _ensureWorkspaceStreamsRoot() {
|
|
11819
|
+
await this._runGraphql(
|
|
11820
|
+
`mutation { create_model(path: "workspace", label: "workspace") { model { path } } }`,
|
|
11821
|
+
"ensure workspace"
|
|
11822
|
+
).catch((error) => {
|
|
11823
|
+
if (!error.message.includes("already exists")) throw error;
|
|
11824
|
+
});
|
|
11825
|
+
await this._runGraphql(
|
|
11826
|
+
`mutation { at(path: "workspace") { create_submodel(subpath: "streams", label: "Streams") { model { path } } } }`,
|
|
11827
|
+
"ensure workspace:streams"
|
|
11828
|
+
).catch((error) => {
|
|
11829
|
+
if (!error.message.includes("already exists")) throw error;
|
|
11830
|
+
});
|
|
11831
|
+
}
|
|
11832
|
+
async _applyEventStreamDeclaration(stream) {
|
|
11833
|
+
await this._ensureWorkspaceStreamsRoot();
|
|
11834
|
+
const streamPath = `workspace:streams:${stream.name}`;
|
|
11835
|
+
await this._runGraphql(
|
|
11836
|
+
`mutation { at(path: "workspace:streams") { create_submodel(subpath: ${JSON.stringify(stream.name)}, label: ${JSON.stringify(stream.name)}) { model { path } } } }`,
|
|
11837
|
+
`create stream ${stream.name}`
|
|
11838
|
+
).catch((error) => {
|
|
11839
|
+
if (!error.message.includes("already exists")) throw error;
|
|
11840
|
+
});
|
|
11841
|
+
if (stream.description) {
|
|
11842
|
+
await this._runGraphql(
|
|
11843
|
+
`mutation { at(path: ${JSON.stringify(streamPath)}) { set_description(description: ${JSON.stringify(stream.description)}) { done } } }`,
|
|
11844
|
+
`set stream description on ${streamPath}`
|
|
11845
|
+
);
|
|
11846
|
+
}
|
|
11847
|
+
for (const eventType of stream.eventTypes) {
|
|
11848
|
+
const typePath = `${streamPath}:${eventType.name}`;
|
|
11849
|
+
await this._runGraphql(
|
|
11850
|
+
`mutation { at(path: ${JSON.stringify(streamPath)}) { create_submodel(subpath: ${JSON.stringify(eventType.name)}, label: ${JSON.stringify(eventType.name)}) { model { path } } } }`,
|
|
11851
|
+
`create event type ${eventType.name} on ${streamPath}`
|
|
11852
|
+
).catch((error) => {
|
|
11853
|
+
if (!error.message.includes("already exists")) throw error;
|
|
11854
|
+
});
|
|
11855
|
+
if (eventType.description) {
|
|
11856
|
+
await this._runGraphql(
|
|
11857
|
+
`mutation { at(path: ${JSON.stringify(typePath)}) { set_description(description: ${JSON.stringify(eventType.description)}) { done } } }`,
|
|
11858
|
+
`set event type description on ${typePath}`
|
|
11859
|
+
);
|
|
11860
|
+
}
|
|
11861
|
+
if (eventType.payloadSchema?.properties) {
|
|
11862
|
+
const fieldSpecs = {};
|
|
11863
|
+
for (const [propName, propSchema] of Object.entries(eventType.payloadSchema.properties)) {
|
|
11864
|
+
const schema = propSchema;
|
|
11865
|
+
fieldSpecs[propName] = {
|
|
11866
|
+
type: schema.type ?? "string",
|
|
11867
|
+
description: schema.description
|
|
11868
|
+
};
|
|
11869
|
+
}
|
|
11870
|
+
await this._applyFields(typePath, fieldSpecs);
|
|
11871
|
+
}
|
|
11872
|
+
if (eventType.payloadSchema?.required?.length) {
|
|
11873
|
+
await this._runGraphql(
|
|
11874
|
+
`mutation { at(path: ${JSON.stringify(typePath)}) { create_submodel(subpath: "required", label: "required") { set_string_value(value: ${JSON.stringify(JSON.stringify(eventType.payloadSchema.required))}) { done } } } }`,
|
|
11875
|
+
`store required fields on ${typePath}`
|
|
11876
|
+
).catch((error) => {
|
|
11877
|
+
if (!error.message.includes("already exists")) throw error;
|
|
11878
|
+
});
|
|
11879
|
+
}
|
|
11880
|
+
}
|
|
11881
|
+
}
|
|
11818
11882
|
async _applyEffectDeclaration(effect, aliasMap) {
|
|
11819
11883
|
let containerPath = "workspace:tools:declared";
|
|
11820
11884
|
if (effect.attachedClass) {
|
|
@@ -11902,6 +11966,9 @@ var Environment = class extends Session {
|
|
|
11902
11966
|
if (op.withEffect) {
|
|
11903
11967
|
await this._applyEffectDeclaration(op.withEffect, aliasMap);
|
|
11904
11968
|
}
|
|
11969
|
+
if (op.defineEventStream) {
|
|
11970
|
+
await this._applyEventStreamDeclaration(op.defineEventStream);
|
|
11971
|
+
}
|
|
11905
11972
|
}
|
|
11906
11973
|
/**
|
|
11907
11974
|
* Apply field definitions (has) to a model via GraphQL
|
|
@@ -12874,6 +12941,107 @@ var Granular = class _Granular {
|
|
|
12874
12941
|
}
|
|
12875
12942
|
};
|
|
12876
12943
|
}
|
|
12944
|
+
/**
|
|
12945
|
+
* Event stream operations: query, subscribe, and acknowledge stream events
|
|
12946
|
+
*/
|
|
12947
|
+
get streams() {
|
|
12948
|
+
return {
|
|
12949
|
+
getEvents: async (params) => {
|
|
12950
|
+
const sandbox = await this._resolveSandboxId(params.ontology);
|
|
12951
|
+
const query = new URLSearchParams({ sandboxId: sandbox });
|
|
12952
|
+
if (params.environment) query.set("environmentId", params.environment);
|
|
12953
|
+
if (params.session) query.set("sessionId", params.session);
|
|
12954
|
+
if (params.stream) query.set("streamName", params.stream);
|
|
12955
|
+
if (params.eventTypes && params.eventTypes.length > 0) {
|
|
12956
|
+
query.set("eventTypes", params.eventTypes.join(","));
|
|
12957
|
+
}
|
|
12958
|
+
if (params.since) query.set("since", params.since.toISOString());
|
|
12959
|
+
if (params.until) query.set("until", params.until.toISOString());
|
|
12960
|
+
if (params.isAcked !== void 0) query.set("isAcked", params.isAcked ? "1" : "0");
|
|
12961
|
+
if (params.limit) query.set("limit", String(params.limit));
|
|
12962
|
+
if (params.offset) query.set("offset", String(params.offset));
|
|
12963
|
+
const result = await this.request(`/control/stream-events?${query.toString()}`);
|
|
12964
|
+
return (result.items || []).map((row) => ({
|
|
12965
|
+
eventId: row.event_id,
|
|
12966
|
+
streamName: row.stream_name,
|
|
12967
|
+
eventType: row.event_type,
|
|
12968
|
+
payload: typeof row.payload === "string" ? JSON.parse(row.payload) : row.payload,
|
|
12969
|
+
environmentId: row.environment_id,
|
|
12970
|
+
sessionId: row.session_id,
|
|
12971
|
+
subjectId: row.subject_id,
|
|
12972
|
+
source: row.source,
|
|
12973
|
+
isAcked: Boolean(row.is_acked),
|
|
12974
|
+
createdAt: row.created_at
|
|
12975
|
+
}));
|
|
12976
|
+
},
|
|
12977
|
+
subscribe: (params) => {
|
|
12978
|
+
const interval = params.pollIntervalMs ?? 5e3;
|
|
12979
|
+
let cursor = params.since || /* @__PURE__ */ new Date();
|
|
12980
|
+
let running = true;
|
|
12981
|
+
const seenEventIds = /* @__PURE__ */ new Set();
|
|
12982
|
+
const poll = async () => {
|
|
12983
|
+
while (running) {
|
|
12984
|
+
try {
|
|
12985
|
+
const events = await this.streams.getEvents({
|
|
12986
|
+
ontology: params.ontology,
|
|
12987
|
+
stream: params.stream,
|
|
12988
|
+
environment: params.environment,
|
|
12989
|
+
session: params.session,
|
|
12990
|
+
eventTypes: params.eventTypes,
|
|
12991
|
+
since: cursor,
|
|
12992
|
+
limit: 100
|
|
12993
|
+
});
|
|
12994
|
+
const orderedEvents = [...events].sort((a, b) => a.createdAt - b.createdAt);
|
|
12995
|
+
for (const event of orderedEvents) {
|
|
12996
|
+
if (seenEventIds.has(event.eventId)) {
|
|
12997
|
+
continue;
|
|
12998
|
+
}
|
|
12999
|
+
seenEventIds.add(event.eventId);
|
|
13000
|
+
const eventTime = new Date(event.createdAt * 1e3);
|
|
13001
|
+
if (eventTime > cursor) {
|
|
13002
|
+
cursor = eventTime;
|
|
13003
|
+
}
|
|
13004
|
+
params.onEvent(event);
|
|
13005
|
+
}
|
|
13006
|
+
} catch (err) {
|
|
13007
|
+
params.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
13008
|
+
}
|
|
13009
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
13010
|
+
}
|
|
13011
|
+
};
|
|
13012
|
+
poll();
|
|
13013
|
+
return { unsubscribe: () => {
|
|
13014
|
+
running = false;
|
|
13015
|
+
} };
|
|
13016
|
+
},
|
|
13017
|
+
ack: async (eventId) => {
|
|
13018
|
+
await this.request("/control/stream-events/ack", {
|
|
13019
|
+
method: "POST",
|
|
13020
|
+
body: JSON.stringify({ eventIds: [eventId] })
|
|
13021
|
+
});
|
|
13022
|
+
},
|
|
13023
|
+
ackBatch: async (eventIds) => {
|
|
13024
|
+
await this.request("/control/stream-events/ack", {
|
|
13025
|
+
method: "POST",
|
|
13026
|
+
body: JSON.stringify({ eventIds })
|
|
13027
|
+
});
|
|
13028
|
+
},
|
|
13029
|
+
getStats: async (params) => {
|
|
13030
|
+
const sandbox = await this._resolveSandboxId(params.ontology);
|
|
13031
|
+
const query = new URLSearchParams({ sandboxId: sandbox });
|
|
13032
|
+
if (params.environment) query.set("environmentId", params.environment);
|
|
13033
|
+
const result = await this.request(`/control/stream-events/stats?${query.toString()}`);
|
|
13034
|
+
return (result.items || []).map((row) => ({
|
|
13035
|
+
streamName: row.stream_name,
|
|
13036
|
+
eventType: row.event_type,
|
|
13037
|
+
total: Number(row.total),
|
|
13038
|
+
last1h: Number(row.last_1h),
|
|
13039
|
+
last24h: Number(row.last_24h),
|
|
13040
|
+
unacked: Number(row.unacked)
|
|
13041
|
+
}));
|
|
13042
|
+
}
|
|
13043
|
+
};
|
|
13044
|
+
}
|
|
12877
13045
|
/**
|
|
12878
13046
|
* Subject management
|
|
12879
13047
|
*/
|
|
@@ -12907,6 +13075,12 @@ var Granular = class _Granular {
|
|
|
12907
13075
|
}
|
|
12908
13076
|
};
|
|
12909
13077
|
}
|
|
13078
|
+
async _resolveSandboxId(ontologyNameOrId) {
|
|
13079
|
+
if (ontologyNameOrId.startsWith("sbx_")) return ontologyNameOrId;
|
|
13080
|
+
const result = await this.request(`/control/sandboxes?name=${encodeURIComponent(ontologyNameOrId)}`);
|
|
13081
|
+
if (result.items.length === 0) throw new Error(`Ontology not found: ${ontologyNameOrId}`);
|
|
13082
|
+
return result.items[0].sandboxId;
|
|
13083
|
+
}
|
|
12910
13084
|
/**
|
|
12911
13085
|
* Make an authenticated API request
|
|
12912
13086
|
*/
|