@roostorg/types 1.0.49 → 1.1.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.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@roostorg/types",
3
3
  "type": "module",
4
- "version": "1.0.49",
5
- "description": "Shared types across Cove services",
4
+ "version": "1.1.0",
5
+ "description": "Shared types across Coop services",
6
6
  "module": "transpiled/index.js",
7
7
  "typings": "./transpiled/index.d.ts",
8
8
  "scripts": {
@@ -10,7 +10,7 @@
10
10
  "prepublishOnly": "npm run build",
11
11
  "test": "npm run build && node --test transpiled/test_scripts/"
12
12
  },
13
- "author": "",
13
+ "author": "Roostorg",
14
14
  "files": [
15
15
  "transpiled"
16
16
  ],
@@ -98,9 +98,6 @@ export type FieldScalarType<T extends FieldType> = T extends ScalarType ? T : Sc
98
98
  * ScalarTypes.GEOHASH are both represented as strings), so, without the label,
99
99
  * we wouldn't know unambiguously which ScalarType a value belongs to, which we
100
100
  * need sometimes (e.g., when deciding whether we can pass it to a signal).
101
- *
102
- * For why this type is written this way, see
103
- * https://github.com/protegoapi/protego/pull/20#discussion_r883974513
104
101
  */
105
102
  type EnumScalarType = ScalarTypes['STRING'] | ScalarTypes['NUMBER'];
106
103
  export type TaggedScalar<T extends ScalarType> = {
@@ -159,9 +156,6 @@ export declare function isMediaValue<T extends ScalarType>(it: TaggedScalar<T>):
159
156
  * legal values in the enum like.
160
157
  */
161
158
  export declare function makeEnumLike<T extends string>(strings: readonly T[]): { [K in T]: K; };
162
- export declare const hiveProjectNames: readonly ["Visual", "Text", "Speech", "OCR", "Demographic"];
163
- export type HiveProjectName = (typeof hiveProjectNames)[number];
164
- export declare function isHiveProjectName(name: string): name is HiveProjectName;
165
159
  export type SignalSubcategory = {
166
160
  id: string;
167
161
  label: string;
@@ -196,4 +190,5 @@ export declare const ItemTypeKind: {
196
190
  USER: "USER";
197
191
  };
198
192
  export type ItemTypeKind = keyof typeof ItemTypeKind;
199
- export {};
193
+ export type { CoopIntegrationConfigEntry, CoopIntegrationPlugin, CoopIntegrationsConfig, IntegrationCredentialField, IntegrationId, IntegrationManifest, ModelCard, ModelCardField, ModelCardSection, ModelCardSubsection, StoredIntegrationConfigPayload, } from './integration.js';
194
+ export { assertModelCardHasRequiredSections, isCoopIntegrationPlugin, REQUIRED_MODEL_CARD_SECTION_IDS, } from './integration.js';
@@ -3,7 +3,7 @@ import { isValid, parseJSON } from 'date-fns';
3
3
  // type is probably not ideal.
4
4
  //
5
5
  // NB: the ID type refers to ids for any type of entity, but USER_ID should be
6
- // used instead for fields that hold ids of users protego might know about. E.g.,
6
+ // used instead for fields that hold ids of users coop might know about. E.g.,
7
7
  // imagine a `Message` content type. Both the `to` and `from` fields could hold
8
8
  // ScalarTypes.USER_IDs, and then a rule could flag the message if _either_ the
9
9
  // sender or the recipient satisfies some condition (after passing the user id
@@ -84,16 +84,6 @@ export function isMediaValue(it) {
84
84
  export function makeEnumLike(strings) {
85
85
  return Object.fromEntries(strings.map((it) => [it, it]));
86
86
  }
87
- export const hiveProjectNames = [
88
- 'Visual',
89
- 'Text',
90
- 'Speech',
91
- 'OCR',
92
- 'Demographic',
93
- ];
94
- export function isHiveProjectName(name) {
95
- return hiveProjectNames.includes(name);
96
- }
97
87
  export function parseDateString(it) {
98
88
  return new Date(it);
99
89
  }
@@ -110,3 +100,4 @@ export function makeDateString(it) {
110
100
  : undefined;
111
101
  }
112
102
  export const ItemTypeKind = makeEnumLike(['CONTENT', 'THREAD', 'USER']);
103
+ export { assertModelCardHasRequiredSections, isCoopIntegrationPlugin, REQUIRED_MODEL_CARD_SECTION_IDS, } from './integration.js';
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Integration plugin types for COOP.
3
+ *
4
+ * These types define the contract that third-party integration packages
5
+ * implement so adopters can install and configure them without adding
6
+ * every integration to the main COOP repo.
7
+ *
8
+ * Integration packages export a CoopIntegrationPlugin; adopters register
9
+ * them via an integrations config file (see CoopIntegrationsConfig).
10
+ */
11
+ /** Unique identifier for the integration (e.g. "GOOGLE_CONTENT_SAFETY_API"). */
12
+ export type IntegrationId = string;
13
+ /**
14
+ * A single key-value row in a model card (e.g. "Release Date" -> "January 2026").
15
+ * Values are plain strings; the UI can linkify URLs or format as needed.
16
+ */
17
+ export type ModelCardField = Readonly<{
18
+ label: string;
19
+ value: string;
20
+ }>;
21
+ /**
22
+ * A named group of fields within a section (e.g. "Basic Information" with
23
+ * Model Name, Version, Release Date). Rendered as a bold subheading + key-value list.
24
+ */
25
+ export type ModelCardSubsection = Readonly<{
26
+ title: string;
27
+ fields: readonly ModelCardField[];
28
+ }>;
29
+ /**
30
+ * One collapsible section of a model card (e.g. "Model Details", "Training Data").
31
+ * Either subsections (with bold sub-headings) or top-level fields, or both.
32
+ */
33
+ export type ModelCardSection = Readonly<{
34
+ /** Stable id for the section (e.g. "modelDetails", "trainingData"). */
35
+ id: string;
36
+ /** Display title (e.g. "Model Details"). */
37
+ title: string;
38
+ /** Optional grouped key-value blocks with their own titles. */
39
+ subsections?: readonly ModelCardSubsection[];
40
+ /** Optional flat key-value list when there are no subsections. */
41
+ fields?: readonly ModelCardField[];
42
+ }>;
43
+ /**
44
+ * Model card: structured, JSON-backed metadata for an integration, so the UI
45
+ * can display it in a consistent but integration-specific way.
46
+ *
47
+ * Required: modelName and version (always shown). All sections are optional;
48
+ * the UI renders only those present. Sections can have subsections (e.g.
49
+ * "Basic Information", "Model Architecture") or flat fields.
50
+ */
51
+ export type ModelCard = Readonly<{
52
+ /** Required. Display name of the model (e.g. "GPT-4"). */
53
+ modelName: string;
54
+ /** Required. Version string (e.g. "1.0.0" or "v0.0"). */
55
+ version: string;
56
+ /** Optional. Release date or similar (e.g. "January 2026"). */
57
+ releaseDate?: string;
58
+ /** Optional. Ordered list of sections; each can be collapsed/expanded in the UI. */
59
+ sections?: readonly ModelCardSection[];
60
+ }>;
61
+ /**
62
+ * Section ids that every integration's model card must include.
63
+ * Use assertModelCardHasRequiredSections() to validate at runtime.
64
+ */
65
+ export declare const REQUIRED_MODEL_CARD_SECTION_IDS: readonly ["modelDetails", "technicalIntegration"];
66
+ /**
67
+ * Asserts that a model card has at least the required sections (basic information
68
+ * and technical integration). Call when registering integration manifests.
69
+ * @throws Error if any required section id is missing
70
+ */
71
+ export declare function assertModelCardHasRequiredSections(card: ModelCard): void;
72
+ /**
73
+ * Describes a single credential field for integrations that require
74
+ * API keys or other secrets. Used to generate or validate credential forms.
75
+ */
76
+ export type IntegrationCredentialField = Readonly<{
77
+ /** Form field key (e.g. "apiKey", "labelerVersions"). */
78
+ key: string;
79
+ /** Human-readable label for the field. */
80
+ label: string;
81
+ /** Whether the field is required. */
82
+ required: boolean;
83
+ /** Input type for the UI. */
84
+ inputType: 'text' | 'password' | 'json' | 'array';
85
+ /** Optional placeholder or hint. */
86
+ placeholder?: string;
87
+ /** Optional description for the field. */
88
+ description?: string;
89
+ }>;
90
+ /**
91
+ * Metadata and capability description for an integration.
92
+ * This is the stable, structured information shown to users (name, docs, logos, etc.).
93
+ */
94
+ export type IntegrationManifest = Readonly<{
95
+ /** Unique integration id. Must be UPPER_SNAKE_CASE to align with GraphQL enums when used in COOP. */
96
+ id: IntegrationId;
97
+ /** Human-readable display name (e.g. "Google Content Safety API"). */
98
+ name: string;
99
+ /** Semantic version of the integration plugin (e.g. "1.0.0"). */
100
+ version: string;
101
+ /** Short description for listings and tooltips. */
102
+ description?: string;
103
+ /** Link to documentation or product page. */
104
+ docsUrl?: string;
105
+ /** Optional URL to a logo image (or asset key if using a bundler). */
106
+ logoUrl?: string;
107
+ /** Optional URL to a logo variant (e.g. with background) for cards. */
108
+ logoWithBackgroundUrl?: string;
109
+ /** Whether this integration requires the user to supply credentials (e.g. API key). */
110
+ requiresCredentials: boolean;
111
+ /**
112
+ * Schema for credential fields when requiresCredentials is true.
113
+ * Enables UI generation and validation without hardcoding per-integration forms.
114
+ */
115
+ credentialFields?: readonly IntegrationCredentialField[];
116
+ /**
117
+ * Optional list of signal type ids this integration provides (e.g. "ZENTROPI_LABELER").
118
+ * Used by the platform to associate signals with this integration for display and gating.
119
+ */
120
+ signalTypeIds?: readonly string[];
121
+ /**
122
+ * Model card: structured metadata (model name, version, sections) for the UI.
123
+ * When present, the integration detail page renders it. Built-in integrations
124
+ * should always provide a model card with at least sections "modelDetails" and
125
+ * "technicalIntegration"; use assertModelCardHasRequiredSections() when
126
+ * registering.
127
+ */
128
+ modelCard?: ModelCard;
129
+ }>;
130
+ /**
131
+ * Plugin contract that third-party integration packages must implement.
132
+ * Export this as the default export (or a named export) from the package.
133
+ *
134
+ * Example (in an integration package):
135
+ *
136
+ * const manifest: IntegrationManifest = { id: 'ACME_API', name: 'Acme API', ... };
137
+ * const plugin: CoopIntegrationPlugin = { manifest };
138
+ * export default plugin;
139
+ */
140
+ export type CoopIntegrationPlugin = Readonly<{
141
+ manifest: IntegrationManifest;
142
+ /**
143
+ * Optional static config shape for this integration.
144
+ * If present, adopters can pass non-secret config in the integrations config file.
145
+ */
146
+ configSchema?: unknown;
147
+ }>;
148
+ /**
149
+ * Single entry in the adopters' integrations config file.
150
+ * Enables or disables a plugin and optionally passes static config.
151
+ */
152
+ export type CoopIntegrationConfigEntry = Readonly<{
153
+ /** NPM package name (e.g. "@acme/coop-integration-acme") or path to a local module. */
154
+ package: string;
155
+ /** Whether this integration is enabled. Default true if omitted. */
156
+ enabled?: boolean;
157
+ /** Optional static config passed to the integration (no secrets here; use org credentials in-app). */
158
+ config?: Readonly<Record<string, unknown>>;
159
+ }>;
160
+ /**
161
+ * Root type for the integrations config file that adopters use to register
162
+ * plugin integrations. Can be JSON or a JS/TS module that exports this shape.
163
+ *
164
+ * Example integrations.config.json:
165
+ *
166
+ * {
167
+ * "integrations": [
168
+ * { "package": "@acme/coop-integration-acme", "enabled": true },
169
+ * { "package": "./local-integrations/foo", "config": { "endpoint": "https://..." } }
170
+ * ]
171
+ * }
172
+ */
173
+ export type CoopIntegrationsConfig = Readonly<{
174
+ integrations: readonly CoopIntegrationConfigEntry[];
175
+ }>;
176
+ /**
177
+ * Shape of the config stored in the database for each integration (per org).
178
+ * Stored in a generic table as JSON: one row per (org_id, integration_id) with
179
+ * config as a JSON-serializable object. Each integration defines its own required
180
+ * fields via IntegrationManifest.credentialFields; the app validates and
181
+ * serializes/deserializes to this type.
182
+ *
183
+ * Only JSON-serializable values (no functions, symbols, or BigInt) should be
184
+ * included so the payload can be stored in a JSONB or TEXT column.
185
+ */
186
+ export type StoredIntegrationConfigPayload = Readonly<Record<string, unknown>>;
187
+ /**
188
+ * Type guard for CoopIntegrationPlugin.
189
+ */
190
+ export declare function isCoopIntegrationPlugin(value: unknown): value is CoopIntegrationPlugin;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Integration plugin types for COOP.
3
+ *
4
+ * These types define the contract that third-party integration packages
5
+ * implement so adopters can install and configure them without adding
6
+ * every integration to the main COOP repo.
7
+ *
8
+ * Integration packages export a CoopIntegrationPlugin; adopters register
9
+ * them via an integrations config file (see CoopIntegrationsConfig).
10
+ */
11
+ /**
12
+ * Section ids that every integration's model card must include.
13
+ * Use assertModelCardHasRequiredSections() to validate at runtime.
14
+ */
15
+ export const REQUIRED_MODEL_CARD_SECTION_IDS = [
16
+ 'modelDetails',
17
+ 'technicalIntegration',
18
+ ];
19
+ /**
20
+ * Asserts that a model card has at least the required sections (basic information
21
+ * and technical integration). Call when registering integration manifests.
22
+ * @throws Error if any required section id is missing
23
+ */
24
+ export function assertModelCardHasRequiredSections(card) {
25
+ const sectionIds = new Set((card.sections ?? []).map((s) => s.id));
26
+ for (const requiredId of REQUIRED_MODEL_CARD_SECTION_IDS) {
27
+ if (!sectionIds.has(requiredId)) {
28
+ throw new Error(`Model card must include a section with id "${requiredId}" (e.g. Basic Information / Model Details and Technical Integration).`);
29
+ }
30
+ }
31
+ }
32
+ /**
33
+ * Type guard for CoopIntegrationPlugin.
34
+ */
35
+ export function isCoopIntegrationPlugin(value) {
36
+ if (value == null || typeof value !== 'object') {
37
+ return false;
38
+ }
39
+ const o = value;
40
+ if (o.manifest == null || typeof o.manifest !== 'object') {
41
+ return false;
42
+ }
43
+ const m = o.manifest;
44
+ return (typeof m.id === 'string' &&
45
+ typeof m.name === 'string' &&
46
+ typeof m.version === 'string' &&
47
+ typeof m.requiresCredentials === 'boolean');
48
+ }