@superblocksteam/shared 0.9607.1 → 0.9607.3

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 (72) hide show
  1. package/dist/types/ai/index.d.ts +4 -0
  2. package/dist/types/ai/index.d.ts.map +1 -1
  3. package/dist/types/ai/index.js.map +1 -1
  4. package/dist/types/application/index.d.ts +34 -0
  5. package/dist/types/application/index.d.ts.map +1 -1
  6. package/dist/types/application/index.js +48 -1
  7. package/dist/types/application/index.js.map +1 -1
  8. package/dist/types/application/index.test.js +61 -0
  9. package/dist/types/application/index.test.js.map +1 -1
  10. package/dist/types/event/index.d.ts +23 -1
  11. package/dist/types/event/index.d.ts.map +1 -1
  12. package/dist/types/event/index.js +4 -0
  13. package/dist/types/event/index.js.map +1 -1
  14. package/dist/types/organization/agent.d.ts +2 -1
  15. package/dist/types/organization/agent.d.ts.map +1 -1
  16. package/dist/types/organization/agent.js.map +1 -1
  17. package/dist/types/organization/index.d.ts +2 -1
  18. package/dist/types/organization/index.d.ts.map +1 -1
  19. package/dist/types/organization/index.js.map +1 -1
  20. package/dist/utils/index.d.ts +8 -7
  21. package/dist/utils/index.d.ts.map +1 -1
  22. package/dist/utils/index.js +8 -7
  23. package/dist/utils/index.js.map +1 -1
  24. package/dist/utils/maskCredential.d.ts +10 -0
  25. package/dist/utils/maskCredential.d.ts.map +1 -0
  26. package/dist/utils/maskCredential.js +17 -0
  27. package/dist/utils/maskCredential.js.map +1 -0
  28. package/dist/utils/maskCredential.test.d.ts +2 -0
  29. package/dist/utils/maskCredential.test.d.ts.map +1 -0
  30. package/dist/utils/maskCredential.test.js +16 -0
  31. package/dist/utils/maskCredential.test.js.map +1 -0
  32. package/dist-esm/types/ai/index.d.ts +4 -0
  33. package/dist-esm/types/ai/index.d.ts.map +1 -1
  34. package/dist-esm/types/ai/index.js.map +1 -1
  35. package/dist-esm/types/application/index.d.ts +34 -0
  36. package/dist-esm/types/application/index.d.ts.map +1 -1
  37. package/dist-esm/types/application/index.js +46 -0
  38. package/dist-esm/types/application/index.js.map +1 -1
  39. package/dist-esm/types/application/index.test.js +62 -1
  40. package/dist-esm/types/application/index.test.js.map +1 -1
  41. package/dist-esm/types/event/index.d.ts +23 -1
  42. package/dist-esm/types/event/index.d.ts.map +1 -1
  43. package/dist-esm/types/event/index.js +4 -0
  44. package/dist-esm/types/event/index.js.map +1 -1
  45. package/dist-esm/types/organization/agent.d.ts +2 -1
  46. package/dist-esm/types/organization/agent.d.ts.map +1 -1
  47. package/dist-esm/types/organization/agent.js.map +1 -1
  48. package/dist-esm/types/organization/index.d.ts +2 -1
  49. package/dist-esm/types/organization/index.d.ts.map +1 -1
  50. package/dist-esm/types/organization/index.js.map +1 -1
  51. package/dist-esm/utils/index.d.ts +8 -7
  52. package/dist-esm/utils/index.d.ts.map +1 -1
  53. package/dist-esm/utils/index.js +8 -7
  54. package/dist-esm/utils/index.js.map +1 -1
  55. package/dist-esm/utils/maskCredential.d.ts +10 -0
  56. package/dist-esm/utils/maskCredential.d.ts.map +1 -0
  57. package/dist-esm/utils/maskCredential.js +13 -0
  58. package/dist-esm/utils/maskCredential.js.map +1 -0
  59. package/dist-esm/utils/maskCredential.test.d.ts +2 -0
  60. package/dist-esm/utils/maskCredential.test.d.ts.map +1 -0
  61. package/dist-esm/utils/maskCredential.test.js +14 -0
  62. package/dist-esm/utils/maskCredential.test.js.map +1 -0
  63. package/package.json +1 -1
  64. package/src/types/ai/index.ts +5 -0
  65. package/src/types/application/index.test.ts +84 -1
  66. package/src/types/application/index.ts +50 -0
  67. package/src/types/event/index.ts +23 -1
  68. package/src/types/organization/agent.ts +2 -1
  69. package/src/types/organization/index.ts +2 -1
  70. package/src/utils/index.ts +8 -7
  71. package/src/utils/maskCredential.test.ts +17 -0
  72. package/src/utils/maskCredential.ts +14 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maskCredential.js","sourceRoot":"","sources":["../../src/utils/maskCredential.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C,wFAAwF;AACxF,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAE7C;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAU,EAAE;IACpD,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC;IACtD,OAAO,GAAG,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,0BAA0B,CAAC,EAAE,CAAC;AAC9D,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=maskCredential.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maskCredential.test.d.ts","sourceRoot":"","sources":["../../src/utils/maskCredential.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { maskCredential } from './maskCredential.js';
3
+ describe('maskCredential', () => {
4
+ it('shows the first 4 characters followed by asterisks', () => {
5
+ expect(maskCredential('abcdEFGHijklMNOP')).toBe('abcd**************');
6
+ });
7
+ it('masks a short key without exposing more than the prefix length', () => {
8
+ expect(maskCredential('ab')).toBe('ab**************');
9
+ });
10
+ it('returns only asterisks for an empty string', () => {
11
+ expect(maskCredential('')).toBe('**************');
12
+ });
13
+ });
14
+ //# sourceMappingURL=maskCredential.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maskCredential.test.js","sourceRoot":"","sources":["../../src/utils/maskCredential.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superblocksteam/shared",
3
- "version": "0.9607.1",
3
+ "version": "0.9607.3",
4
4
  "description": "Superblocks Shared Resources",
5
5
  "license": "Superblocks Community Software License",
6
6
  "repository": "https://github.com/superblocksteam/shared.git",
@@ -1,3 +1,5 @@
1
+ import { DeploymentTypeEnum, RegionEnum } from '../common/index.js';
2
+
1
3
  export type AiChatMessagePayload = Record<string, unknown>;
2
4
 
3
5
  export type AiChatMessageDto = {
@@ -92,6 +94,9 @@ export interface AiWorkflowAttributes {
92
94
  export interface AiWorkflowEvent {
93
95
  promptId: string;
94
96
  attributes: AiWorkflowAttributes;
97
+ region?: RegionEnum;
98
+ deploymentType?: DeploymentTypeEnum;
99
+ deploymentName?: string;
95
100
  }
96
101
 
97
102
  /**
@@ -1,6 +1,16 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+
1
4
  import { describe, expect, it } from 'vitest';
2
5
 
3
- import { effectiveCommitTemplateName, isSdkApiCommitTemplate, isSdkApiTemplate, LEGACY_COMMIT_TEMPLATE_NAME } from './index';
6
+ import {
7
+ ApplicationType,
8
+ effectiveCommitTemplateName,
9
+ getApplicationType,
10
+ isSdkApiCommitTemplate,
11
+ isSdkApiTemplate,
12
+ LEGACY_COMMIT_TEMPLATE_NAME
13
+ } from './index';
4
14
 
5
15
  describe('SDK API application templates', () => {
6
16
  it('classifies app-fullstack as the 3.0 SDK API template', () => {
@@ -20,3 +30,76 @@ describe('SDK API application templates', () => {
20
30
  expect(effectiveCommitTemplateName(null)).toBe(LEGACY_COMMIT_TEMPLATE_NAME);
21
31
  });
22
32
  });
33
+
34
+ describe('getApplicationType', () => {
35
+ it('classifies an application with devEnvEnabled=false as 1.0', () => {
36
+ expect(getApplicationType({ devEnvEnabled: false, templateName: null })).toBe(ApplicationType.V1);
37
+ });
38
+
39
+ it('classifies a legacy 1.0 application as 1.0 even when a template name is present', () => {
40
+ // devEnvEnabled is the 1.0 vs 2.0+ discriminator; template name alone never promotes a 1.0 app.
41
+ expect(getApplicationType({ devEnvEnabled: false, templateName: 'app-fullstack' })).toBe(ApplicationType.V1);
42
+ });
43
+
44
+ it.each([null, 'shadcn-demo-app', 'blank-app'])('classifies a code-mode application on template %s as 2.0', (templateName) => {
45
+ expect(getApplicationType({ devEnvEnabled: true, templateName })).toBe(ApplicationType.V2);
46
+ });
47
+
48
+ it('classifies a code-mode application on an SDK API template as 3.0', () => {
49
+ expect(getApplicationType({ devEnvEnabled: true, templateName: 'app-fullstack' })).toBe(ApplicationType.V3);
50
+ });
51
+
52
+ it.each([undefined, null])('returns undefined when devEnvEnabled was not projected (%s) by the query', (devEnvEnabled) => {
53
+ // dev_env_enabled is NOT NULL DEFAULT false, so a nullish value means unselected.
54
+ expect(getApplicationType({ devEnvEnabled, templateName: 'app-fullstack' })).toBeUndefined();
55
+ });
56
+
57
+ it('returns undefined when templateName was not projected for a code-mode app', () => {
58
+ // Guessing 2.0 here would silently misclassify every 3.0 app behind a partial select.
59
+ expect(getApplicationType({ devEnvEnabled: true })).toBeUndefined();
60
+ });
61
+
62
+ it('does not need templateName to classify a legacy app', () => {
63
+ expect(getApplicationType({ devEnvEnabled: false })).toBe(ApplicationType.V1);
64
+ });
65
+
66
+ it('treats a genuinely null template as a real value, not an unprojected one', () => {
67
+ expect(getApplicationType({ devEnvEnabled: true, templateName: null })).toBe(ApplicationType.V2);
68
+ });
69
+
70
+ it('does not classify from a commit-scoped template resolution', () => {
71
+ // A commit predating a 2.0 -> 3.0 migration resolves to the legacy template.
72
+ // Classifying off that instead of the app row is what would misreport 3.0 as 2.0.
73
+ const migratedAppRow = { devEnvEnabled: true, templateName: 'app-fullstack' };
74
+ const preMigrationCommitTemplate = effectiveCommitTemplateName(null);
75
+
76
+ expect(getApplicationType(migratedAppRow)).toBe(ApplicationType.V3);
77
+ expect(getApplicationType({ devEnvEnabled: true, templateName: preMigrationCommitTemplate })).toBe(ApplicationType.V2);
78
+ });
79
+
80
+ it('exposes the version strings the analytics pipeline filters on', () => {
81
+ expect(ApplicationType.V1).toBe('1.0');
82
+ expect(ApplicationType.V2).toBe('2.0');
83
+ expect(ApplicationType.V3).toBe('3.0');
84
+ });
85
+ });
86
+
87
+ describe('SDK_API_TEMPLATES stays in sync with the demo-apps template config', () => {
88
+ // isSdkApiTemplate drives the 3.0-vs-2.0 half of getApplicationType, which is a
89
+ // billing input. A new SDK API template shipped without updating the allowlist
90
+ // would not fail safe -- it would confidently classify those apps as 2.0. The
91
+ // template config is the source of truth, so pin the two together here rather
92
+ // than relying on the "must stay in sync" comment alone.
93
+ // This package compiles to CommonJS, so import.meta is unavailable; vitest runs
94
+ // with the package directory as cwd.
95
+ const configPath = resolve(process.cwd(), '../demo-apps/config.json');
96
+ const templates = (JSON.parse(readFileSync(configPath, 'utf8')) as { templates: Record<string, { sdkApi?: boolean }> }).templates;
97
+
98
+ it('has at least one template to check', () => {
99
+ expect(Object.keys(templates).length).toBeGreaterThan(0);
100
+ });
101
+
102
+ it.each(Object.entries(templates))('agrees with config.json on whether %s is an SDK API template', (name, template) => {
103
+ expect(isSdkApiTemplate(name)).toBe(template.sdkApi === true);
104
+ });
105
+ });
@@ -659,6 +659,56 @@ export function isSdkApiTemplate(templateName: string | null | undefined): boole
659
659
  return SDK_API_TEMPLATES.has(templateName);
660
660
  }
661
661
 
662
+ /**
663
+ * The product generation an application belongs to, as reported to analytics and
664
+ * billing. The values are the customer-facing version labels so downstream
665
+ * consumers (Snowflake, billing) can filter on them directly.
666
+ */
667
+ export enum ApplicationType {
668
+ /** Legacy drag-and-drop application (not code mode). */
669
+ V1 = '1.0',
670
+ /** Code-mode application on a non-SDK-API template. */
671
+ V2 = '2.0',
672
+ /** Code-mode application on an SDK API template. */
673
+ V3 = '3.0'
674
+ }
675
+
676
+ /**
677
+ * Classifies an application as 1.0 / 2.0 / 3.0 from the two fields that already
678
+ * live on the application row: `dev_env_enabled` separates legacy (1.0) from
679
+ * code-mode (2.0+), and the SDK API template separates 3.0 from 2.0. A 2.0 to
680
+ * 3.0 migration is a `template_name` flip on the same application row, so this
681
+ * classification follows the app across a migration with no extra lookup.
682
+ *
683
+ * Both inputs must come from the application ROW. In particular `templateName`
684
+ * must not be a commit's effective template (see `effectiveCommitTemplateName`):
685
+ * a commit predating a 2.0 to 3.0 migration resolves to the legacy template and
686
+ * would misreport a 3.0 app as 2.0.
687
+ *
688
+ * Returns `undefined` when the app cannot be classified because a field was not
689
+ * projected by the caller's query. `undefined` is distinguishable from a real
690
+ * `null` template (a legacy template, a valid 2.0 value), so an unselected
691
+ * column yields no answer instead of a confidently wrong one.
692
+ */
693
+ export function getApplicationType(application: {
694
+ devEnvEnabled?: boolean | null;
695
+ templateName?: string | null;
696
+ }): ApplicationType | undefined {
697
+ // `dev_env_enabled` is NOT NULL DEFAULT false, so a nullish value here means
698
+ // the column was not selected rather than a legitimate absence.
699
+ if (application.devEnvEnabled == null) {
700
+ return undefined;
701
+ }
702
+ if (!application.devEnvEnabled) {
703
+ return ApplicationType.V1;
704
+ }
705
+ // `template_name` IS nullable, so only `undefined` means "not projected".
706
+ if (application.templateName === undefined) {
707
+ return undefined;
708
+ }
709
+ return isSdkApiTemplate(application.templateName) ? ApplicationType.V3 : ApplicationType.V2;
710
+ }
711
+
662
712
  /**
663
713
  * The legacy template name that commits predating the per-commit `template_name`
664
714
  * column are treated as. NULL on `application_commit.template_name` means the
@@ -1,4 +1,5 @@
1
- import { RegionEnum } from '../common/index.js';
1
+ import { type ApplicationType } from '../application/index.js';
2
+ import { DeploymentTypeEnum, RegionEnum } from '../common/index.js';
2
3
  import { RequestSource } from '../user/index.js';
3
4
 
4
5
  export enum EventEntityType {
@@ -18,6 +19,7 @@ export enum EventEntityType {
18
19
  SURVEY = 'survey',
19
20
  ACCOUNT = 'account',
20
21
  BILLING = 'billing',
22
+ BUILDER_LICENSE = 'builder_license',
21
23
  OBSERVABILITY = 'observability',
22
24
  GROUP = 'group',
23
25
  ORGANIZATION_INVITES = 'organization_invites',
@@ -71,15 +73,18 @@ export enum EventAction {
71
73
  DEPLOYED = 'deployed',
72
74
  UNDEPLOYED = 'undeployed',
73
75
  IMPORTED = 'imported',
76
+ MIGRATED = 'migrated',
74
77
  EXECUTED = 'executed',
75
78
  EXPORTED = 'exported',
76
79
  VIEWED = 'viewed',
77
80
  STARTED = 'started',
78
81
  FINISHED = 'finished',
79
82
  ADDED = 'added',
83
+ ASSIGNED = 'assigned',
80
84
  PAUSED = 'paused',
81
85
  RESUMED = 'resumed',
82
86
  UPDATED = 'updated',
87
+ UNASSIGNED = 'unassigned',
83
88
  PATCHED = 'patched',
84
89
  METADATA_UPDATED = 'metadata_updated',
85
90
  SETTINGS_UPDATED = 'settings_updated',
@@ -124,12 +129,29 @@ export interface UserEvent {
124
129
  properties?: Record<string, any>;
125
130
  createdAt: Date;
126
131
  region?: RegionEnum;
132
+ deploymentType?: DeploymentTypeEnum;
133
+ deploymentName?: string;
127
134
  source?: RequestSource;
128
135
  }
129
136
 
130
137
  export interface EventEntity {
131
138
  id: string;
132
139
  name: string | undefined;
140
+ /**
141
+ * Product generation (1.0 / 2.0 / 3.0), stamped onto `* application` events.
142
+ *
143
+ * Populated only by `applicationEventEntity()`, which classifies from the
144
+ * application row. No `ApplicationV2` or `ApplicationV2Dto` carries a field of
145
+ * this name, so passing one of those directly leaves it unset rather than
146
+ * supplying a value of unknown grain -- but note that is a naming convention,
147
+ * not something the type system enforces: `newEvent` accepts any `EventEntity`,
148
+ * so a future field with this name would be picked up structurally.
149
+ *
150
+ * Left undefined whenever the caller cannot classify the app (only an id in
151
+ * hand, or a query that did not project the needed columns). An absent property
152
+ * beats a guessed one -- a wrong generation is worse for billing than none.
153
+ */
154
+ applicationType?: ApplicationType;
133
155
  }
134
156
 
135
157
  export enum EventSource {
@@ -44,7 +44,8 @@ export enum AgentsHealthStatus {
44
44
 
45
45
  export type Agent = {
46
46
  id: string;
47
- key: string;
47
+ /** Registration key; omitted on ordinary API reads (SEC-43). */
48
+ key?: string;
48
49
  environment: string;
49
50
  status: AgentStatus;
50
51
  version: string;
@@ -44,7 +44,8 @@ export interface Organization {
44
44
  name: string;
45
45
  domains?: Domain[];
46
46
  agents?: Agent[];
47
- apiKey: string;
47
+ /** Live ORG_USER key; omitted on ordinary reads (SEC-43). Use execution-token endpoints. */
48
+ apiKey?: string;
48
49
  agentType: AgentType;
49
50
  minExternalAgentVersion: string;
50
51
  pluginExecutionVersions?: PluginExecutionVersions;
@@ -1,18 +1,19 @@
1
- export * from './configuration.js';
2
- export * from './attachment-upload.js';
1
+ export * from './apiv2.js';
3
2
  export * from './attachment-delivery.js';
3
+ export * from './attachment-upload.js';
4
+ export * from './bytestring.js';
5
+ export * from './configuration.js';
4
6
  export * from './env.js';
5
7
  export * from './environment.js';
6
8
  export * from './git-url.js';
9
+ export * from './maskCredential.js';
10
+ export * from './normalize.js';
11
+ export * from './normalizeRoleName.js';
12
+ export * from './page.js';
7
13
  export * from './string.js';
8
14
  export * from './time.js';
9
15
  export * from './truncate.js';
10
16
  export * from './url.js';
11
- export * from './bytestring.js';
12
- export * from './apiv2.js';
13
- export * from './page.js';
14
- export * from './normalize.js';
15
- export * from './normalizeRoleName.js';
16
17
 
17
18
  import gridV4 from './pageFixtures/v4/grid.js';
18
19
  export { gridV4 };
@@ -0,0 +1,17 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { maskCredential } from './maskCredential.js';
4
+
5
+ describe('maskCredential', () => {
6
+ it('shows the first 4 characters followed by asterisks', () => {
7
+ expect(maskCredential('abcdEFGHijklMNOP')).toBe('abcd**************');
8
+ });
9
+
10
+ it('masks a short key without exposing more than the prefix length', () => {
11
+ expect(maskCredential('ab')).toBe('ab**************');
12
+ });
13
+
14
+ it('returns only asterisks for an empty string', () => {
15
+ expect(maskCredential('')).toBe('**************');
16
+ });
17
+ });
@@ -0,0 +1,14 @@
1
+ /** Number of leading characters shown for identification on credential display surfaces. */
2
+ export const CREDENTIAL_PREFIX_LENGTH = 4;
3
+
4
+ /** Fixed asterisk pad length for masked credentials (does not encode secret length). */
5
+ export const CREDENTIAL_MASK_PAD_LENGTH = 14;
6
+
7
+ /**
8
+ * Mask a credential for UI display: first {@link CREDENTIAL_PREFIX_LENGTH} characters
9
+ * plus a fixed asterisk pad. The full secret must never be returned on ordinary reads.
10
+ */
11
+ export const maskCredential = (key: string): string => {
12
+ const prefix = key.slice(0, CREDENTIAL_PREFIX_LENGTH);
13
+ return `${prefix}${'*'.repeat(CREDENTIAL_MASK_PAD_LENGTH)}`;
14
+ };