@undefineds.co/xpod 0.3.67 → 0.3.69

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 (47) hide show
  1. package/config/components-ignore.json +1 -0
  2. package/dist/api/ApiServer.d.ts +9 -1
  3. package/dist/api/ApiServer.js +22 -1
  4. package/dist/api/ApiServer.js.map +1 -1
  5. package/dist/api/container/common.js +1 -1
  6. package/dist/api/container/common.js.map +1 -1
  7. package/dist/api/container/routes.js +13 -0
  8. package/dist/api/container/routes.js.map +1 -1
  9. package/dist/api/container/types.d.ts +1 -1
  10. package/dist/api/container/types.js.map +1 -1
  11. package/dist/api/handlers/DeviceNotificationRuntime.d.ts +26 -0
  12. package/dist/api/handlers/DeviceNotificationRuntime.js +77 -0
  13. package/dist/api/handlers/DeviceNotificationRuntime.js.map +1 -0
  14. package/dist/api/handlers/DeviceNotificationTicketHandler.d.ts +50 -0
  15. package/dist/api/handlers/DeviceNotificationTicketHandler.js +130 -0
  16. package/dist/api/handlers/DeviceNotificationTicketHandler.js.map +1 -0
  17. package/dist/api/handlers/DeviceNotificationTicketHandler.jsonld +117 -0
  18. package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
  19. package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
  20. package/dist/components/components.jsonld +6 -1
  21. package/dist/components/context.jsonld +122 -0
  22. package/dist/http/DeviceNotificationWebSocketServer.d.ts +29 -0
  23. package/dist/http/DeviceNotificationWebSocketServer.js +138 -0
  24. package/dist/http/DeviceNotificationWebSocketServer.js.map +1 -0
  25. package/dist/http/DeviceNotificationWebSocketServer.jsonld +148 -0
  26. package/dist/index.d.ts +7 -1
  27. package/dist/index.js +13 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/notifications/DeviceNotificationHub.d.ts +74 -0
  30. package/dist/notifications/DeviceNotificationHub.js +313 -0
  31. package/dist/notifications/DeviceNotificationHub.js.map +1 -0
  32. package/dist/notifications/DeviceNotificationHub.jsonld +258 -0
  33. package/dist/notifications/DeviceNotificationResourceListener.d.ts +21 -0
  34. package/dist/notifications/DeviceNotificationResourceListener.js +38 -0
  35. package/dist/notifications/DeviceNotificationResourceListener.js.map +1 -0
  36. package/dist/notifications/DeviceNotificationResourceListener.jsonld +98 -0
  37. package/dist/notifications/device-notification-protocol.d.ts +56 -0
  38. package/dist/notifications/device-notification-protocol.js +127 -0
  39. package/dist/notifications/device-notification-protocol.js.map +1 -0
  40. package/dist/notifications/device-notification-protocol.jsonld +29 -0
  41. package/dist/notifications/index.d.ts +3 -0
  42. package/dist/notifications/index.js +20 -0
  43. package/dist/notifications/index.js.map +1 -0
  44. package/dist/storage/ObservableResourceStore.d.ts +3 -0
  45. package/dist/storage/ObservableResourceStore.js +17 -1
  46. package/dist/storage/ObservableResourceStore.js.map +1 -1
  47. package/package.json +1 -1
@@ -0,0 +1,3 @@
1
+ export * from './device-notification-protocol';
2
+ export * from './DeviceNotificationHub';
3
+ export * from './DeviceNotificationResourceListener';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./device-notification-protocol"), exports);
18
+ __exportStar(require("./DeviceNotificationHub"), exports);
19
+ __exportStar(require("./DeviceNotificationResourceListener"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/notifications/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iEAA+C;AAC/C,0DAAwC;AACxC,uEAAqD","sourcesContent":["export * from './device-notification-protocol';\nexport * from './DeviceNotificationHub';\nexport * from './DeviceNotificationResourceListener';\n"]}
@@ -46,6 +46,7 @@ export interface ObservableResourceStoreOptions {
46
46
  * 3. 事件异步处理,不阻塞主流程
47
47
  */
48
48
  export declare class ObservableResourceStore<T extends ResourceStore = ResourceStore> extends PassthroughStore<T> {
49
+ private static readonly globalListeners;
49
50
  protected readonly logger: import("global-logger-factory").Logger<unknown>;
50
51
  private readonly emitter;
51
52
  private readonly listeners;
@@ -54,6 +55,8 @@ export declare class ObservableResourceStore<T extends ResourceStore = ResourceS
54
55
  * 添加监听器
55
56
  */
56
57
  addListener(listener: ResourceChangeListener): void;
58
+ static addGlobalListener(listener: ResourceChangeListener): void;
59
+ static removeGlobalListener(listener: ResourceChangeListener): void;
57
60
  /**
58
61
  * 移除监听器
59
62
  */
@@ -35,6 +35,17 @@ class ObservableResourceStore extends community_server_1.PassthroughStore {
35
35
  addListener(listener) {
36
36
  this.listeners.push(listener);
37
37
  }
38
+ static addGlobalListener(listener) {
39
+ if (!this.globalListeners.includes(listener)) {
40
+ this.globalListeners.push(listener);
41
+ }
42
+ }
43
+ static removeGlobalListener(listener) {
44
+ const index = this.globalListeners.indexOf(listener);
45
+ if (index !== -1) {
46
+ this.globalListeners.splice(index, 1);
47
+ }
48
+ }
38
49
  /**
39
50
  * 移除监听器
40
51
  */
@@ -102,7 +113,11 @@ class ObservableResourceStore extends community_server_1.PassthroughStore {
102
113
  * 通知所有监听器
103
114
  */
104
115
  notifyListeners(event) {
105
- for (const listener of this.listeners) {
116
+ const listeners = new Set([
117
+ ...ObservableResourceStore.globalListeners,
118
+ ...this.listeners,
119
+ ]);
120
+ for (const listener of listeners) {
106
121
  listener.onResourceChanged(event).catch((error) => {
107
122
  this.logger.error(`Listener error for ${event.path}: ${error}`);
108
123
  });
@@ -122,4 +137,5 @@ class ObservableResourceStore extends community_server_1.PassthroughStore {
122
137
  }
123
138
  }
124
139
  exports.ObservableResourceStore = ObservableResourceStore;
140
+ ObservableResourceStore.globalListeners = [];
125
141
  //# sourceMappingURL=ObservableResourceStore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ObservableResourceStore.js","sourceRoot":"","sources":["../../src/storage/ObservableResourceStore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ObservableResourceStore - 可观察的资源存储包装器\n *\n * 在资源变更时发出事件,供订阅者(如 UsageTracker、VectorIndexer)处理。\n * 采用事件驱动模式,解耦存储操作与副作用逻辑。\n */\n\nimport { EventEmitter } from 'node:events';\nimport { PassthroughStore } from '@solid/community-server';\nimport type {\n ChangeMap,\n Representation,\n RepresentationPreferences,\n ResourceIdentifier,\n Conditions,\n ResourceStore,\n} from '@solid/community-server';\nimport { getLoggerFor } from 'global-logger-factory';\n\n/**\n * 资源变更事件类型\n */\nexport type ResourceChangeAction = 'create' | 'update' | 'delete';\n\n/**\n * 资源变更事件\n */\nexport interface ResourceChangeEvent {\n /** 资源路径 */\n path: string;\n /** 变更类型 */\n action: ResourceChangeAction;\n /** 是否为容器 */\n isContainer: boolean;\n /** 变更时间戳 */\n timestamp: number;\n}\n\n/**\n * 资源变更监听器接口\n */\nexport interface ResourceChangeListener {\n /**\n * 处理资源变更事件\n * @param event 变更事件\n */\n onResourceChanged(event: ResourceChangeEvent): Promise<void>;\n}\n\nexport interface ObservableResourceStoreOptions {\n /** 资源变更监听器列表 */\n listeners?: ResourceChangeListener[];\n}\n\n/**\n * ObservableResourceStore - 在资源变更时发出事件\n *\n * 使用方式:\n * 1. 作为 Store 链的包装层\n * 2. 注册 listeners 处理变更事件\n * 3. 事件异步处理,不阻塞主流程\n */\nexport class ObservableResourceStore<T extends ResourceStore = ResourceStore> extends PassthroughStore<T> {\n protected readonly logger = getLoggerFor(this);\n private readonly emitter = new EventEmitter();\n private readonly listeners: ResourceChangeListener[];\n\n public constructor(source: T, options: ObservableResourceStoreOptions = {}) {\n super(source);\n this.listeners = options.listeners ?? [];\n\n // 注册内部事件处理\n this.emitter.on('resource:changed', (event: ResourceChangeEvent) => {\n this.notifyListeners(event);\n });\n }\n\n /**\n * 添加监听器\n */\n public addListener(listener: ResourceChangeListener): void {\n this.listeners.push(listener);\n }\n\n /**\n * 移除监听器\n */\n public removeListener(listener: ResourceChangeListener): void {\n const index = this.listeners.indexOf(listener);\n if (index !== -1) {\n this.listeners.splice(index, 1);\n }\n }\n\n /**\n * 添加资源(创建新资源)\n */\n public override async addResource(\n container: ResourceIdentifier,\n representation: Representation,\n conditions?: Conditions,\n ): Promise<ChangeMap> {\n const change = await super.addResource(container, representation, conditions);\n\n // 从 ChangeMap 中获取新创建的资源路径\n for (const [identifier] of change) {\n this.emitChange(identifier.path, 'create');\n }\n\n return change;\n }\n\n /**\n * 设置资源(创建或更新)\n */\n public override async setRepresentation(\n identifier: ResourceIdentifier,\n representation: Representation,\n conditions?: Conditions,\n ): Promise<ChangeMap> {\n // 检查资源是否已存在\n const exists = await this.resourceExists(identifier);\n const action: ResourceChangeAction = exists ? 'update' : 'create';\n\n const change = await super.setRepresentation(identifier, representation, conditions);\n\n this.emitChange(identifier.path, action);\n\n return change;\n }\n\n /**\n * 删除资源\n */\n public override async deleteResource(\n identifier: ResourceIdentifier,\n conditions?: Conditions,\n ): Promise<ChangeMap> {\n const change = await super.deleteResource(identifier, conditions);\n\n this.emitChange(identifier.path, 'delete');\n\n return change;\n }\n\n /**\n * 修改资源(PATCH)\n */\n public override async modifyResource(\n identifier: ResourceIdentifier,\n patch: Representation,\n conditions?: Conditions,\n ): Promise<ChangeMap> {\n const change = await super.modifyResource(identifier, patch, conditions);\n\n this.emitChange(identifier.path, 'update');\n\n return change;\n }\n\n /**\n * 发出资源变更事件\n */\n private emitChange(path: string, action: ResourceChangeAction): void {\n const event: ResourceChangeEvent = {\n path,\n action,\n isContainer: path.endsWith('/'),\n timestamp: Date.now(),\n };\n\n this.logger.debug(`Resource ${action}: ${path}`);\n\n // 异步发出事件,不阻塞主流程\n setImmediate(() => {\n this.emitter.emit('resource:changed', event);\n });\n }\n\n /**\n * 通知所有监听器\n */\n private notifyListeners(event: ResourceChangeEvent): void {\n for (const listener of this.listeners) {\n listener.onResourceChanged(event).catch((error) => {\n this.logger.error(`Listener error for ${event.path}: ${error}`);\n });\n }\n }\n\n /**\n * 检查资源是否存在\n */\n private async resourceExists(identifier: ResourceIdentifier): Promise<boolean> {\n try {\n await this.source.getRepresentation(identifier, {} as RepresentationPreferences);\n return true;\n } catch {\n return false;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ObservableResourceStore.js","sourceRoot":"","sources":["../../src/storage/ObservableResourceStore.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,6CAA2C;AAC3C,8DAA2D;AAS3D,iEAAqD;AAqCrD;;;;;;;GAOG;AACH,MAAa,uBAAiE,SAAQ,mCAAmB;IAOvG,YAAmB,MAAS,EAAE,UAA0C,EAAE;QACxE,KAAK,CAAC,MAAM,CAAC,CAAC;QALG,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAC9B,YAAO,GAAG,IAAI,0BAAY,EAAE,CAAC;QAK5C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;QAEzC,WAAW;QACX,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,kBAAkB,EAAE,CAAC,KAA0B,EAAE,EAAE;YACjE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACI,WAAW,CAAC,QAAgC;QACjD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAEM,MAAM,CAAC,iBAAiB,CAAC,QAAgC;QAC9D,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAEM,MAAM,CAAC,oBAAoB,CAAC,QAAgC;QACjE,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED;;OAEG;IACI,cAAc,CAAC,QAAgC;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED;;OAEG;IACa,KAAK,CAAC,WAAW,CAC/B,SAA6B,EAC7B,cAA8B,EAC9B,UAAuB;QAEvB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;QAE9E,0BAA0B;QAC1B,KAAK,MAAM,CAAC,UAAU,CAAC,IAAI,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACa,KAAK,CAAC,iBAAiB,CACrC,UAA8B,EAC9B,cAA8B,EAC9B,UAAuB;QAEvB,YAAY;QACZ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,MAAM,GAAyB,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QAElE,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,iBAAiB,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;QAErF,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAEzC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACa,KAAK,CAAC,cAAc,CAClC,UAA8B,EAC9B,UAAuB;QAEvB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAElE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAE3C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACa,KAAK,CAAC,cAAc,CAClC,UAA8B,EAC9B,KAAqB,EACrB,UAAuB;QAEvB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QAEzE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAE3C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,UAAU,CAAC,IAAY,EAAE,MAA4B;QAC3D,MAAM,KAAK,GAAwB;YACjC,IAAI;YACJ,MAAM;YACN,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAC/B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;QAEjD,gBAAgB;QAChB,YAAY,CAAC,GAAG,EAAE;YAChB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,KAA0B;QAChD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;YACxB,GAAG,uBAAuB,CAAC,eAAe;YAC1C,GAAG,IAAI,CAAC,SAAS;SAClB,CAAC,CAAC;QACH,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBAChD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC;YAClE,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,cAAc,CAAC,UAA8B;QACzD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,UAAU,EAAE,EAA+B,CAAC,CAAC;YACjF,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;;AA7JH,0DA8JC;AA7JyB,uCAAe,GAA6B,EAAE,AAA/B,CAAgC","sourcesContent":["/**\n * ObservableResourceStore - 可观察的资源存储包装器\n *\n * 在资源变更时发出事件,供订阅者(如 UsageTracker、VectorIndexer)处理。\n * 采用事件驱动模式,解耦存储操作与副作用逻辑。\n */\n\nimport { EventEmitter } from 'node:events';\nimport { PassthroughStore } from '@solid/community-server';\nimport type {\n ChangeMap,\n Representation,\n RepresentationPreferences,\n ResourceIdentifier,\n Conditions,\n ResourceStore,\n} from '@solid/community-server';\nimport { getLoggerFor } from 'global-logger-factory';\n\n/**\n * 资源变更事件类型\n */\nexport type ResourceChangeAction = 'create' | 'update' | 'delete';\n\n/**\n * 资源变更事件\n */\nexport interface ResourceChangeEvent {\n /** 资源路径 */\n path: string;\n /** 变更类型 */\n action: ResourceChangeAction;\n /** 是否为容器 */\n isContainer: boolean;\n /** 变更时间戳 */\n timestamp: number;\n}\n\n/**\n * 资源变更监听器接口\n */\nexport interface ResourceChangeListener {\n /**\n * 处理资源变更事件\n * @param event 变更事件\n */\n onResourceChanged(event: ResourceChangeEvent): Promise<void>;\n}\n\nexport interface ObservableResourceStoreOptions {\n /** 资源变更监听器列表 */\n listeners?: ResourceChangeListener[];\n}\n\n/**\n * ObservableResourceStore - 在资源变更时发出事件\n *\n * 使用方式:\n * 1. 作为 Store 链的包装层\n * 2. 注册 listeners 处理变更事件\n * 3. 事件异步处理,不阻塞主流程\n */\nexport class ObservableResourceStore<T extends ResourceStore = ResourceStore> extends PassthroughStore<T> {\n private static readonly globalListeners: ResourceChangeListener[] = [];\n\n protected readonly logger = getLoggerFor(this);\n private readonly emitter = new EventEmitter();\n private readonly listeners: ResourceChangeListener[];\n\n public constructor(source: T, options: ObservableResourceStoreOptions = {}) {\n super(source);\n this.listeners = options.listeners ?? [];\n\n // 注册内部事件处理\n this.emitter.on('resource:changed', (event: ResourceChangeEvent) => {\n this.notifyListeners(event);\n });\n }\n\n /**\n * 添加监听器\n */\n public addListener(listener: ResourceChangeListener): void {\n this.listeners.push(listener);\n }\n\n public static addGlobalListener(listener: ResourceChangeListener): void {\n if (!this.globalListeners.includes(listener)) {\n this.globalListeners.push(listener);\n }\n }\n\n public static removeGlobalListener(listener: ResourceChangeListener): void {\n const index = this.globalListeners.indexOf(listener);\n if (index !== -1) {\n this.globalListeners.splice(index, 1);\n }\n }\n\n /**\n * 移除监听器\n */\n public removeListener(listener: ResourceChangeListener): void {\n const index = this.listeners.indexOf(listener);\n if (index !== -1) {\n this.listeners.splice(index, 1);\n }\n }\n\n /**\n * 添加资源(创建新资源)\n */\n public override async addResource(\n container: ResourceIdentifier,\n representation: Representation,\n conditions?: Conditions,\n ): Promise<ChangeMap> {\n const change = await super.addResource(container, representation, conditions);\n\n // 从 ChangeMap 中获取新创建的资源路径\n for (const [identifier] of change) {\n this.emitChange(identifier.path, 'create');\n }\n\n return change;\n }\n\n /**\n * 设置资源(创建或更新)\n */\n public override async setRepresentation(\n identifier: ResourceIdentifier,\n representation: Representation,\n conditions?: Conditions,\n ): Promise<ChangeMap> {\n // 检查资源是否已存在\n const exists = await this.resourceExists(identifier);\n const action: ResourceChangeAction = exists ? 'update' : 'create';\n\n const change = await super.setRepresentation(identifier, representation, conditions);\n\n this.emitChange(identifier.path, action);\n\n return change;\n }\n\n /**\n * 删除资源\n */\n public override async deleteResource(\n identifier: ResourceIdentifier,\n conditions?: Conditions,\n ): Promise<ChangeMap> {\n const change = await super.deleteResource(identifier, conditions);\n\n this.emitChange(identifier.path, 'delete');\n\n return change;\n }\n\n /**\n * 修改资源(PATCH)\n */\n public override async modifyResource(\n identifier: ResourceIdentifier,\n patch: Representation,\n conditions?: Conditions,\n ): Promise<ChangeMap> {\n const change = await super.modifyResource(identifier, patch, conditions);\n\n this.emitChange(identifier.path, 'update');\n\n return change;\n }\n\n /**\n * 发出资源变更事件\n */\n private emitChange(path: string, action: ResourceChangeAction): void {\n const event: ResourceChangeEvent = {\n path,\n action,\n isContainer: path.endsWith('/'),\n timestamp: Date.now(),\n };\n\n this.logger.debug(`Resource ${action}: ${path}`);\n\n // 异步发出事件,不阻塞主流程\n setImmediate(() => {\n this.emitter.emit('resource:changed', event);\n });\n }\n\n /**\n * 通知所有监听器\n */\n private notifyListeners(event: ResourceChangeEvent): void {\n const listeners = new Set([\n ...ObservableResourceStore.globalListeners,\n ...this.listeners,\n ]);\n for (const listener of listeners) {\n listener.onResourceChanged(event).catch((error) => {\n this.logger.error(`Listener error for ${event.path}: ${error}`);\n });\n }\n }\n\n /**\n * 检查资源是否存在\n */\n private async resourceExists(identifier: ResourceIdentifier): Promise<boolean> {\n try {\n await this.source.getRepresentation(identifier, {} as RepresentationPreferences);\n return true;\n } catch {\n return false;\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/xpod",
3
- "version": "0.3.67",
3
+ "version": "0.3.69",
4
4
  "description": "Xpod is an extended Community Solid Server, offering rich-feature, production-level Solid Pod and identity management.",
5
5
  "repository": "https://github.com/undefinedsco/xpod",
6
6
  "author": "developer@undefineds.co",