@noodleseed/one 0.161.2 → 0.162.0

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 (60) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +3 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/catalog.d.ts.map +1 -1
  5. package/dist/commands/catalog.js +1 -0
  6. package/dist/commands/catalog.js.map +1 -1
  7. package/dist/commands/solutions-ops.d.ts +7 -0
  8. package/dist/commands/solutions-ops.d.ts.map +1 -0
  9. package/dist/commands/solutions-ops.js +283 -0
  10. package/dist/commands/solutions-ops.js.map +1 -0
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js +4 -0
  16. package/node_modules/@noodle-borg/agent-kit/dist/curated/error-fixes.js +2 -1
  17. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +3 -3
  18. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +3 -0
  19. package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +7 -0
  20. package/node_modules/@noodle-borg/authoring/dist/index.d.ts +1 -0
  21. package/node_modules/@noodle-borg/authoring/dist/index.js +1 -0
  22. package/node_modules/@noodle-borg/authoring/dist/load-authored.js +1 -1
  23. package/node_modules/@noodle-borg/authoring/dist/managed-collection.d.ts +26 -0
  24. package/node_modules/@noodle-borg/authoring/dist/managed-collection.js +20 -0
  25. package/node_modules/@noodle-borg/authoring/dist/server.d.ts +3 -0
  26. package/node_modules/@noodle-borg/authoring/dist/server.js +2 -0
  27. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-tenant-resources.js +241 -0
  28. package/node_modules/@noodle-borg/compiler/dist/artifact/assemble.js +4 -1
  29. package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +10 -0
  30. package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +4 -1
  31. package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +4 -1
  32. package/node_modules/@noodle-borg/compiler/dist/compile.js +3 -0
  33. package/node_modules/@noodle-borg/compiler/dist/errors.d.ts +1 -1
  34. package/node_modules/@noodle-borg/compiler/dist/index.d.ts +2 -1
  35. package/node_modules/@noodle-borg/compiler/dist/index.js +1 -0
  36. package/node_modules/@noodle-borg/compiler/dist/managed-collections.d.ts +25 -0
  37. package/node_modules/@noodle-borg/compiler/dist/managed-collections.js +184 -0
  38. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +14 -0
  39. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +3 -0
  40. package/node_modules/@noodle-borg/service/dist/business-information/contracts.js +5 -0
  41. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-store.js +402 -0
  42. package/node_modules/@noodle-borg/service/dist/business-information/model.js +292 -0
  43. package/node_modules/@noodle-borg/service/dist/business-information/pagination.js +50 -0
  44. package/node_modules/@noodle-borg/service/dist/business-information/portable.js +6 -0
  45. package/node_modules/@noodle-borg/service/dist/business-information/profiles.js +121 -0
  46. package/node_modules/@noodle-borg/service/dist/business-information/validation.js +200 -0
  47. package/node_modules/@noodle-borg/service/dist/oauth/store.d.ts +2 -2
  48. package/node_modules/@noodle-borg/service/dist/routes/business-information-dispatch.js +48 -0
  49. package/node_modules/@noodle-borg/service/dist/routes/business-information-paths.js +92 -0
  50. package/node_modules/@noodle-borg/service/dist/routes/business-information-wire.js +117 -0
  51. package/node_modules/@noodle-borg/service/dist/routes/business-information.js +551 -0
  52. package/node_modules/@noodle-borg/service/dist/service-resource-cleanup.js +2 -0
  53. package/node_modules/@noodle-borg/service/dist/service.js +25 -0
  54. package/node_modules/@noodle-borg/wire-contracts/dist/business-information.d.ts +583 -0
  55. package/node_modules/@noodle-borg/wire-contracts/dist/business-information.js +205 -0
  56. package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +4 -3
  57. package/node_modules/@noodle-borg/wire-contracts/dist/index.js +1 -0
  58. package/node_modules/@noodle-borg/wire-contracts/dist/knowledge.d.ts +3 -3
  59. package/node_modules/@noodle-borg/wire-contracts/dist/managed-assistant-sponsorship.d.ts +8 -8
  60. package/package.json +1 -1
@@ -171,7 +171,7 @@ export interface OAuthStore extends DeviceAuthorizationStore {
171
171
  getClient(clientId: string): Promise<OAuthClientInformationFull | undefined>;
172
172
  putClient(client: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
173
173
  /** Atomically reserves or reconciles a server-owned client without taking over a DCR registration. */
174
- putFirstPartyClient(owner: 'console', client: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
174
+ putFirstPartyClient(owner: 'console' | 'portal', client: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
175
175
  /** Pending authorization (single-use). A provider mismatch leaves the record live for its real callback. */
176
176
  createPendingAuthorization(record: PendingAuthorizationRecord): Promise<void>;
177
177
  consumePendingAuthorization(state: string, expectedUpstreamProvider: PendingAuthorizationCallbackKind): Promise<PendingAuthorizationRecord | undefined>;
@@ -220,7 +220,7 @@ export declare class InMemoryOAuthStore implements OAuthStore {
220
220
  #private;
221
221
  getClient(clientId: string): Promise<OAuthClientInformationFull | undefined>;
222
222
  putClient(client: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
223
- putFirstPartyClient(owner: 'console', client: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
223
+ putFirstPartyClient(owner: 'console' | 'portal', client: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
224
224
  createPendingAuthorization(record: PendingAuthorizationRecord): Promise<void>;
225
225
  consumePendingAuthorization(state: string, expectedUpstreamProvider: PendingAuthorizationRecord['upstreamProvider']): Promise<PendingAuthorizationRecord | undefined>;
226
226
  createAuthorizationCode(record: AuthorizationCodeRecord): Promise<void>;
@@ -0,0 +1,48 @@
1
+ import { respondRouteError } from '../http-util.js';
2
+ import { handleBusinessGrants, handleManagedRecords, handlePublicSolutionIntake, handleSolutionCatalog, handleSolutionInstallations, } from './business-information.js';
3
+ import { parsePublicSolutionIntakePath, parseSolutionInstallationPath, } from './business-information-paths.js';
4
+ export function dispatchBusinessInformationRoutes(req, res, url, deps) {
5
+ if (url.pathname === '/v1/solutions/catalog') {
6
+ return run(req, res, deps, () => Promise.resolve(handleSolutionCatalog(req, res)));
7
+ }
8
+ const publicRef = parsePublicSolutionIntakePath(url.pathname);
9
+ if (publicRef !== undefined) {
10
+ deps.applySecurityHeaders(res, deps.tls);
11
+ if (deps.enforceHttps(req, res, deps.tls))
12
+ return true;
13
+ applyPublicIntakeCors(res);
14
+ if (req.method === 'OPTIONS') {
15
+ res.writeHead(204);
16
+ res.end();
17
+ return true;
18
+ }
19
+ void handlePublicSolutionIntake(req, res, publicRef, deps).catch((error) => respondRouteError(deps.logger, res, 'business_information.public_route.failed', error));
20
+ return true;
21
+ }
22
+ const installationRef = parseSolutionInstallationPath(url.pathname);
23
+ if (installationRef === undefined)
24
+ return false;
25
+ if (installationRef.action === 'grants') {
26
+ return run(req, res, deps, () => handleBusinessGrants(req, res, installationRef, deps));
27
+ }
28
+ if (installationRef.action === 'records' ||
29
+ installationRef.action === 'activity' ||
30
+ installationRef.action === 'export') {
31
+ return run(req, res, deps, () => handleManagedRecords(req, res, url, installationRef, deps));
32
+ }
33
+ return run(req, res, deps, () => handleSolutionInstallations(req, res, installationRef, deps));
34
+ }
35
+ function applyPublicIntakeCors(res) {
36
+ res.setHeader('access-control-allow-origin', '*');
37
+ res.setHeader('access-control-allow-methods', 'GET, POST, OPTIONS');
38
+ res.setHeader('access-control-allow-headers', 'Content-Type, Idempotency-Key');
39
+ res.setHeader('access-control-max-age', '600');
40
+ }
41
+ function run(req, res, deps, handle) {
42
+ deps.applySecurityHeaders(res, deps.tls);
43
+ if (deps.enforceHttps(req, res, deps.tls))
44
+ return true;
45
+ void handle().catch((error) => respondRouteError(deps.logger, res, 'business_information.route.failed', error));
46
+ return true;
47
+ }
48
+ //# sourceMappingURL=business-information-dispatch.js.map
@@ -0,0 +1,92 @@
1
+ function decoded(match, index) {
2
+ const raw = match[index];
3
+ if (raw === undefined)
4
+ return undefined;
5
+ try {
6
+ const value = decodeURIComponent(raw);
7
+ return value.length > 0 && value.length <= 128 ? value : undefined;
8
+ }
9
+ catch {
10
+ return undefined;
11
+ }
12
+ }
13
+ export function parseSolutionInstallationPath(pathname) {
14
+ let match = /^\/v1\/orgs\/([^/]+)\/solution-installations$/.exec(pathname);
15
+ if (match !== null) {
16
+ const org = decoded(match, 1);
17
+ return org === undefined ? undefined : { org };
18
+ }
19
+ match = /^\/v1\/orgs\/([^/]+)\/solution-installations\/([^/]+)$/.exec(pathname);
20
+ if (match !== null) {
21
+ const org = decoded(match, 1);
22
+ const installationId = decoded(match, 2);
23
+ return org === undefined || installationId === undefined ? undefined : { org, installationId };
24
+ }
25
+ match = /^\/v1\/orgs\/([^/]+)\/solution-installations\/([^/]+)\/grants$/.exec(pathname);
26
+ if (match !== null) {
27
+ const org = decoded(match, 1);
28
+ const installationId = decoded(match, 2);
29
+ return org === undefined || installationId === undefined
30
+ ? undefined
31
+ : { org, installationId, action: 'grants' };
32
+ }
33
+ match = /^\/v1\/orgs\/([^/]+)\/solution-installations\/([^/]+)\/grants\/([^/]+)$/.exec(pathname);
34
+ if (match !== null) {
35
+ const org = decoded(match, 1);
36
+ const installationId = decoded(match, 2);
37
+ const subject = decoded(match, 3);
38
+ return org === undefined || installationId === undefined || subject === undefined
39
+ ? undefined
40
+ : { org, installationId, subject, action: 'grants' };
41
+ }
42
+ match =
43
+ /^\/v1\/orgs\/([^/]+)\/solution-installations\/([^/]+)\/collections\/([^/]+)\/records(?:\/(export))?$/.exec(pathname);
44
+ if (match !== null) {
45
+ const org = decoded(match, 1);
46
+ const installationId = decoded(match, 2);
47
+ const collection = decoded(match, 3);
48
+ return org === undefined || installationId === undefined || collection === undefined
49
+ ? undefined
50
+ : {
51
+ org,
52
+ installationId,
53
+ collection,
54
+ action: match[4] === 'export' ? 'export' : 'records',
55
+ };
56
+ }
57
+ match =
58
+ /^\/v1\/orgs\/([^/]+)\/solution-installations\/([^/]+)\/collections\/([^/]+)\/records\/([^/]+)(?:\/(activity))?$/.exec(pathname);
59
+ if (match !== null) {
60
+ const org = decoded(match, 1);
61
+ const installationId = decoded(match, 2);
62
+ const collection = decoded(match, 3);
63
+ const recordId = decoded(match, 4);
64
+ return org === undefined ||
65
+ installationId === undefined ||
66
+ collection === undefined ||
67
+ recordId === undefined
68
+ ? undefined
69
+ : {
70
+ org,
71
+ installationId,
72
+ collection,
73
+ recordId,
74
+ action: match[5] === 'activity' ? 'activity' : 'records',
75
+ };
76
+ }
77
+ return undefined;
78
+ }
79
+ export function parsePublicSolutionIntakePath(pathname) {
80
+ let match = /^\/v1\/solution-intake\/([^/]+)$/.exec(pathname);
81
+ if (match !== null) {
82
+ const publicId = decoded(match, 1);
83
+ return publicId === undefined ? undefined : { publicId };
84
+ }
85
+ match = /^\/v1\/solution-intake\/([^/]+)\/([^/]+)\/records$/.exec(pathname);
86
+ if (match === null)
87
+ return undefined;
88
+ const publicId = decoded(match, 1);
89
+ const collection = decoded(match, 2);
90
+ return publicId === undefined || collection === undefined ? undefined : { publicId, collection };
91
+ }
92
+ //# sourceMappingURL=business-information-paths.js.map
@@ -0,0 +1,117 @@
1
+ export function profileToWire(profile) {
2
+ const collection = profile.collections[0];
3
+ if (collection === undefined)
4
+ throw new Error(`solution profile "${profile.key}" has no collection`);
5
+ return {
6
+ id: profile.key,
7
+ title: profile.label,
8
+ description: `Receive and operate ${collection.labels.plural.toLowerCase()}.`,
9
+ collection: collectionToWire(collection),
10
+ };
11
+ }
12
+ export function collectionToWire(collection) {
13
+ return {
14
+ key: collection.key,
15
+ title: collection.labels.plural,
16
+ singularTitle: collection.labels.singular,
17
+ schemaVersion: collection.schemaVersion,
18
+ schemaDigest: collection.schemaDigest.replace(/^sha256:/, ''),
19
+ recordSchema: { ...collection.schema },
20
+ summaryFields: collection.schema.required.slice(0, 6),
21
+ };
22
+ }
23
+ export function installationToWire(installation, profile, currentRole) {
24
+ const collection = profile.collections.find((candidate) => installation.managedCollections.includes(candidate.key));
25
+ if (collection === undefined)
26
+ throw new Error('solution installation has no active collection');
27
+ return {
28
+ id: installation.scope.installationId,
29
+ organizationId: installation.scope.org,
30
+ profileId: installation.profileKey,
31
+ appSlug: installation.scope.app,
32
+ environment: installation.scope.env,
33
+ retentionDays: installation.retentionDays,
34
+ publicId: installation.publicId,
35
+ active: true,
36
+ currentRole,
37
+ revision: installation.revision,
38
+ collection: collectionToWire(collection),
39
+ createdAt: installation.createdAt,
40
+ updatedAt: installation.updatedAt,
41
+ createdBySubject: installation.createdBySubject,
42
+ };
43
+ }
44
+ export function grantToWire(grant) {
45
+ if (grant.email === undefined)
46
+ throw new Error('business grant has no email');
47
+ return {
48
+ installationId: grant.scope.installationId,
49
+ subject: grant.subject,
50
+ email: grant.email,
51
+ role: grant.role,
52
+ revision: grant.revision,
53
+ createdAt: grant.createdAt,
54
+ createdBySubject: grant.createdBySubject,
55
+ ...(grant.revokedAt === undefined ? {} : { revokedAt: grant.revokedAt }),
56
+ };
57
+ }
58
+ export function recordToWire(record) {
59
+ if (record.deletedAt !== undefined || record.content === undefined) {
60
+ if (record.deletedAt === undefined || record.deletionReason === undefined) {
61
+ throw new Error('managed record tombstone is incomplete');
62
+ }
63
+ return {
64
+ id: record.id,
65
+ installationId: record.scope.installationId,
66
+ collection: record.collectionKey,
67
+ status: record.status,
68
+ revision: record.revision,
69
+ deletedAt: record.deletedAt,
70
+ deletionReason: record.deletionReason,
71
+ };
72
+ }
73
+ return {
74
+ id: record.id,
75
+ installationId: record.scope.installationId,
76
+ collection: record.collectionKey,
77
+ schemaVersion: record.schemaVersion,
78
+ schemaDigest: record.schemaDigest.replace(/^sha256:/, ''),
79
+ payload: record.content.payload,
80
+ status: record.status,
81
+ ...(record.assigneeSubject === undefined ? {} : { assigneeSubject: record.assigneeSubject }),
82
+ revision: record.revision,
83
+ origin: {
84
+ surface: record.origin.kind === 'embedded'
85
+ ? 'public'
86
+ : record.origin.kind === 'import'
87
+ ? 'api'
88
+ : record.origin.kind,
89
+ ...(record.createdBySubject === 'anonymous' ? {} : { subject: record.createdBySubject }),
90
+ },
91
+ createdAt: record.createdAt,
92
+ updatedAt: record.updatedAt,
93
+ retentionExpiresAt: record.retentionExpiresAt,
94
+ };
95
+ }
96
+ const ACTIVITY_OPERATION = {
97
+ created: 'create',
98
+ updated: 'update',
99
+ assigned: 'assign',
100
+ status_changed: 'set-status',
101
+ note_added: 'add-note',
102
+ deleted: 'delete',
103
+ retention_expired: 'delete',
104
+ };
105
+ export function activityToWire(activity) {
106
+ const note = activity.kind === 'note_added' ? activity.content?.notes.at(-1)?.text : undefined;
107
+ return {
108
+ id: `${activity.recordId}:${activity.revision}`,
109
+ recordId: activity.recordId,
110
+ revision: activity.revision,
111
+ operation: ACTIVITY_OPERATION[activity.kind],
112
+ actorSubject: activity.actorSubject,
113
+ createdAt: activity.occurredAt,
114
+ ...(note === undefined ? {} : { note }),
115
+ };
116
+ }
117
+ //# sourceMappingURL=business-information-wire.js.map