@toolproof-npm/schema 0.1.12

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.
@@ -0,0 +1,2 @@
1
+ import schema from './Job.json';
2
+ export default schema;
@@ -0,0 +1,2 @@
1
+ import schema from './Job.json' with { type: 'json' };
2
+ export default schema;
@@ -0,0 +1,161 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "allOf": [
5
+ {
6
+ "$ref": "#/$defs/Documented"
7
+ },
8
+ {
9
+ "$ref": "#/$defs/RolesOuter"
10
+ },
11
+ {
12
+ "$ref": "#/$defs/Uri"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "identity": {
17
+ "type": "string"
18
+ }
19
+ },
20
+ "required": [
21
+ "identity"
22
+ ],
23
+ "unevaluatedProperties": false,
24
+ "$anchor": "Job",
25
+ "$defs": {
26
+ "Documented": {
27
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
28
+ "type": "object",
29
+ "allOf": [
30
+ {
31
+ "$ref": "#/$defs/Name"
32
+ },
33
+ {
34
+ "$ref": "#/$defs/Description"
35
+ }
36
+ ],
37
+ "$anchor": "Documented"
38
+ },
39
+ "RolesOuter": {
40
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
41
+ "type": "object",
42
+ "properties": {
43
+ "roles": {
44
+ "$ref": "#/$defs/RolesInner"
45
+ }
46
+ },
47
+ "required": [
48
+ "roles"
49
+ ],
50
+ "$anchor": "RolesOuter"
51
+ },
52
+ "Uri": {
53
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
54
+ "type": "object",
55
+ "properties": {
56
+ "uri": {
57
+ "type": "string",
58
+ "format": "uri"
59
+ }
60
+ },
61
+ "required": [
62
+ "uri"
63
+ ],
64
+ "$anchor": "Uri"
65
+ },
66
+ "Name": {
67
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
68
+ "type": "object",
69
+ "properties": {
70
+ "name": {
71
+ "type": "string",
72
+ "$comment": "Validation is intercepted by an AI Agent that verifies the name against Toolproof's naming conventions.",
73
+ "minLength": 1,
74
+ "pattern": "^(?:[A-Z].*|[a-z]+/[a-z0-9.+-]+)$",
75
+ "semanticValidation": "Ajv custom keyword to verify name."
76
+ }
77
+ },
78
+ "required": [
79
+ "name"
80
+ ],
81
+ "$anchor": "Name"
82
+ },
83
+ "Description": {
84
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
85
+ "type": "object",
86
+ "properties": {
87
+ "description": {
88
+ "type": "string",
89
+ "$comment": "Validation is intercepted by an AI Agent that verifies the description against Toolproof's documentation standards.",
90
+ "minLength": 1,
91
+ "semanticValidation": "Ajv custom keyword to verify description."
92
+ }
93
+ },
94
+ "required": [
95
+ "description"
96
+ ],
97
+ "$anchor": "Description"
98
+ },
99
+ "RolesInner": {
100
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
101
+ "type": "object",
102
+ "properties": {
103
+ "inputMap": {
104
+ "$ref": "#/$defs/RoleMap"
105
+ },
106
+ "outputMap": {
107
+ "$ref": "#/$defs/RoleMap"
108
+ }
109
+ },
110
+ "required": [
111
+ "inputMap",
112
+ "outputMap"
113
+ ],
114
+ "unevaluatedProperties": false,
115
+ "$anchor": "RolesInner"
116
+ },
117
+ "RoleMap": {
118
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
119
+ "type": "object",
120
+ "additionalProperties": {
121
+ "$ref": "#/$defs/RoleLiteral"
122
+ },
123
+ "$anchor": "RoleMap",
124
+ "propertyNames": {
125
+ "$ref": "#/$defs/RoleId"
126
+ }
127
+ },
128
+ "RoleLiteral": {
129
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
130
+ "type": "object",
131
+ "allOf": [
132
+ {
133
+ "properties": {
134
+ "typeId": {
135
+ "$ref": "#/$defs/TypeId"
136
+ }
137
+ },
138
+ "required": [
139
+ "typeId"
140
+ ]
141
+ },
142
+ {
143
+ "$ref": "#/$defs/Documented"
144
+ }
145
+ ],
146
+ "$anchor": "RoleLiteral"
147
+ },
148
+ "RoleId": {
149
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
150
+ "type": "string",
151
+ "$anchor": "RoleId",
152
+ "pattern": "^ROLE-.+$"
153
+ },
154
+ "TypeId": {
155
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
156
+ "type": "string",
157
+ "$anchor": "TypeId",
158
+ "pattern": "^TYPE-.+$"
159
+ }
160
+ }
161
+ }
@@ -0,0 +1,25 @@
1
+ import type { ExecutionId, ResourceId, WorkStepId, BranchStepId, ForStepId, FormatId, TypeId, RoleId, WhileStepId, WorkflowId, WorkflowSpecId } from "../_lib/types/types.js";
2
+ /** Generic unsafe brand helper when a bespoke factory is not available. */
3
+ export declare function unsafeBrand<T extends string>(s: string): T;
4
+ export declare const asTypeId: (s: string) => `TYPE-${string}`;
5
+ export declare const asRoleId: (s: string) => `ROLE-${string}`;
6
+ export declare const asExecutionId: (s: string) => `EXECUTION-${string}`;
7
+ export declare const asResourceId: (s: string) => `RESOURCE-${string}`;
8
+ export declare const asWorkStepId: (s: string) => `WORKSTEP-${string}`;
9
+ export declare const asBranchStepId: (s: string) => `BRANCHSTEP-${string}`;
10
+ export declare const asForStepId: (s: string) => `FORSTEP-${string}`;
11
+ export declare const asFormatId: (s: string) => `FORMAT-${string}`;
12
+ export declare const asWhileStepId: (s: string) => `WHILESTEP-${string}`;
13
+ export declare const asWorkflowId: (s: string) => `WORKFLOW-${string}`;
14
+ export declare const asWorkflowSpecId: (s: string) => `WORKFLOWSPEC-${string}`;
15
+ export declare const asTypeIds: (xs: string[]) => TypeId[];
16
+ export declare const asRoleIds: (xs: string[]) => RoleId[];
17
+ export declare const asExecutionIds: (xs: string[]) => ExecutionId[];
18
+ export declare const asResourceIds: (xs: string[]) => ResourceId[];
19
+ export declare const asWorkStepIds: (xs: string[]) => WorkStepId[];
20
+ export declare const asBranchStepIds: (xs: string[]) => BranchStepId[];
21
+ export declare const asForStepIds: (xs: string[]) => ForStepId[];
22
+ export declare const asFormatIds: (xs: string[]) => FormatId[];
23
+ export declare const asWhileStepIds: (xs: string[]) => WhileStepId[];
24
+ export declare const asWorkflowIds: (xs: string[]) => WorkflowId[];
25
+ export declare const asWorkflowSpecIds: (xs: string[]) => WorkflowSpecId[];
@@ -0,0 +1,50 @@
1
+ // Runtime factories for branded ID string types.
2
+ // Note: The branded types are declared in src/types/types.d.ts by the generator.
3
+ // We import them as type-only so there is no runtime dependency on the .d.ts file.
4
+ // Optional runtime validation toggle. Off by default.
5
+ // Enable by setting TP_BRAND_VALIDATE=1 (or NODE_ENV=development) when running.
6
+ const shouldValidate = (typeof process !== "undefined" && !!process.env &&
7
+ (process.env.TP_BRAND_VALIDATE === "1" || process.env.NODE_ENV === "development")) ||
8
+ false;
9
+ function makeFactory(name, pattern) {
10
+ return (s) => {
11
+ if (shouldValidate && pattern && !pattern.test(s)) {
12
+ throw new TypeError(`Invalid ${name}: "${s}" does not match ${String(pattern)}`);
13
+ }
14
+ return s;
15
+ };
16
+ }
17
+ /** Generic unsafe brand helper when a bespoke factory is not available. */
18
+ export function unsafeBrand(s) {
19
+ return s;
20
+ }
21
+ // Known patterns from schemas (when available)
22
+ const RE_TYPE_ID = /^TYPE-.+$/;
23
+ const RE_SIGNATURE_ID = /^SIGNATURE-.+$/;
24
+ const RE_JOB_ID = /^JOB-.+$/;
25
+ const RE_ROLE_ID = /^ROLE-.+$/;
26
+ // Factories for each Id-like type
27
+ export const asTypeId = makeFactory("TypeId", RE_TYPE_ID);
28
+ export const asRoleId = makeFactory("RoleId", RE_ROLE_ID);
29
+ // IDs without strict regex patterns in the current schemas: keep unchecked casts.
30
+ export const asExecutionId = makeFactory("ExecutionId");
31
+ export const asResourceId = makeFactory("ResourceId");
32
+ export const asWorkStepId = makeFactory("WorkStepId");
33
+ export const asBranchStepId = makeFactory("BranchStepId");
34
+ export const asForStepId = makeFactory("ForStepId");
35
+ export const asFormatId = makeFactory("FormatId");
36
+ export const asWhileStepId = makeFactory("WhileStepId");
37
+ export const asWorkflowId = makeFactory("WorkflowId");
38
+ export const asWorkflowSpecId = makeFactory("WorkflowSpecId");
39
+ // Batch helpers
40
+ export const asTypeIds = (xs) => xs.map(asTypeId);
41
+ export const asRoleIds = (xs) => xs.map(asRoleId);
42
+ export const asExecutionIds = (xs) => xs.map(asExecutionId);
43
+ export const asResourceIds = (xs) => xs.map(asResourceId);
44
+ export const asWorkStepIds = (xs) => xs.map(asWorkStepId);
45
+ export const asBranchStepIds = (xs) => xs.map(asBranchStepId);
46
+ export const asForStepIds = (xs) => xs.map(asForStepId);
47
+ export const asFormatIds = (xs) => xs.map(asFormatId);
48
+ export const asWhileStepIds = (xs) => xs.map(asWhileStepId);
49
+ export const asWorkflowIds = (xs) => xs.map(asWorkflowId);
50
+ export const asWorkflowSpecIds = (xs) => xs.map(asWorkflowSpecId);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,173 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ function parseArgs() {
5
+ const argv = process.argv.slice(2);
6
+ let inPath = "";
7
+ let outPath = "";
8
+ let topLevelId;
9
+ for (let i = 0; i < argv.length; i++) {
10
+ const a = argv[i];
11
+ if (a === "--in" && i + 1 < argv.length)
12
+ inPath = argv[++i];
13
+ else if (a === "--out" && i + 1 < argv.length)
14
+ outPath = argv[++i];
15
+ else if (a === "--id" && i + 1 < argv.length)
16
+ topLevelId = argv[++i];
17
+ }
18
+ if (!inPath || !outPath) {
19
+ console.error("Usage: node extractSchemas.js --in <Genesis.json> --out <flattened.json> [--id <schemaId>]");
20
+ process.exit(1);
21
+ }
22
+ // Resolve to absolute paths from project root
23
+ const cwd = process.cwd();
24
+ const wasInRelative = !path.isAbsolute(inPath);
25
+ const wasOutRelative = !path.isAbsolute(outPath);
26
+ if (wasInRelative)
27
+ inPath = path.join(cwd, inPath);
28
+ if (wasOutRelative)
29
+ outPath = path.join(cwd, outPath);
30
+ // Fallback: resolve relative to script directory if not found
31
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
32
+ if (!fs.existsSync(inPath) && wasInRelative)
33
+ inPath = path.resolve(scriptDir, inPath);
34
+ const outDir = path.dirname(outPath);
35
+ if (!fs.existsSync(outDir) && wasOutRelative) {
36
+ // Try making directory relative to script dir
37
+ const altOut = path.resolve(scriptDir, outPath);
38
+ const altOutDir = path.dirname(altOut);
39
+ if (!fs.existsSync(path.dirname(outPath))) {
40
+ // Prefer creating outDir at cwd location if possible; otherwise fallback below when writing
41
+ }
42
+ else {
43
+ outPath = altOut;
44
+ }
45
+ }
46
+ return { inPath, outPath, topLevelId };
47
+ }
48
+ // Heuristic: determine if a node is a Type envelope
49
+ function isTypeEnvelope(node) {
50
+ return (node && typeof node === "object" && !Array.isArray(node) &&
51
+ typeof node.id === "string" && node.name && node.extractionSchema && typeof node.extractionSchema === "object");
52
+ }
53
+ // Merge $defs into target, without overwriting existing keys unless identical
54
+ function mergeDefs(target, source, label) {
55
+ if (!source || typeof source !== "object")
56
+ return;
57
+ const src = source["$defs"];
58
+ if (!src || typeof src !== "object")
59
+ return;
60
+ for (const [k, v] of Object.entries(src)) {
61
+ if (!(k in target)) {
62
+ target[k] = v;
63
+ }
64
+ else {
65
+ // Best-effort: if duplicate key, require structural equality; otherwise, namespace
66
+ const existing = JSON.stringify(target[k]);
67
+ const incoming = JSON.stringify(v);
68
+ if (existing !== incoming) {
69
+ const altKey = `${k}__from_${(label || "defs").replace(/[^A-Za-z0-9_]+/g, "_")}`;
70
+ if (!(altKey in target))
71
+ target[altKey] = v;
72
+ }
73
+ }
74
+ }
75
+ }
76
+ // Deeply traverse an object replacing any Type envelope with its extractionSchema,
77
+ // and hoist its inner $defs to topDefs. Prevent infinite recursion with a visited set.
78
+ function unwrapTypes(node, topDefs, labelPath = [], visited = new Set()) {
79
+ if (node && typeof node === "object") {
80
+ if (visited.has(node))
81
+ return node; // avoid cycles
82
+ visited.add(node);
83
+ }
84
+ if (isTypeEnvelope(node)) {
85
+ const env = node;
86
+ const inner = env.extractionSchema;
87
+ // Hoist inner $defs before stripping
88
+ mergeDefs(topDefs, inner, labelPath.join("_"));
89
+ // Return the inner schema itself, after also unwrapping any nested envelopes it may contain
90
+ const unwrappedInner = unwrapTypes(inner, topDefs, labelPath.concat([String(env.id || "env")]), visited);
91
+ return unwrappedInner;
92
+ }
93
+ if (Array.isArray(node)) {
94
+ return node.map((v, i) => unwrapTypes(v, topDefs, labelPath.concat([String(i)]), visited));
95
+ }
96
+ if (node && typeof node === "object") {
97
+ const out = {};
98
+ for (const [k, v] of Object.entries(node)) {
99
+ if (k === "$defs" && v && typeof v === "object" && !Array.isArray(v)) {
100
+ // Process nested $defs: unwrap each entry value if it's a Type envelope
101
+ const defsOut = {};
102
+ for (const [dk, dv] of Object.entries(v)) {
103
+ const unwrapped = unwrapTypes(dv, topDefs, labelPath.concat(["$defs", dk]), visited);
104
+ defsOut[dk] = unwrapped;
105
+ }
106
+ out[k] = defsOut;
107
+ }
108
+ else {
109
+ out[k] = unwrapTypes(v, topDefs, labelPath.concat([k]), visited);
110
+ }
111
+ }
112
+ return out;
113
+ }
114
+ return node;
115
+ }
116
+ function main() {
117
+ const { inPath, outPath, topLevelId } = parseArgs();
118
+ const raw = fs.readFileSync(inPath, "utf8");
119
+ const doc = JSON.parse(raw);
120
+ if (!doc || typeof doc !== "object" || !doc.extractionSchema) {
121
+ throw new Error("Input must be a Type JSON with an extractionSchema at the top level");
122
+ }
123
+ const topSchema = doc.extractionSchema;
124
+ const outDefs = {};
125
+ // Seed with top-level $defs (if any) before unwrapping
126
+ mergeDefs(outDefs, topSchema, "top");
127
+ // Unwrap the entire top schema tree so that any nested Type envelopes become raw schemas
128
+ const flattened = unwrapTypes(topSchema, outDefs, ["extractionSchema"]);
129
+ // Assemble output: force $schema, optionally set $id, hoist collected $defs
130
+ let base;
131
+ if (flattened && typeof flattened === "object" && !Array.isArray(flattened)) {
132
+ base = { ...flattened };
133
+ }
134
+ else {
135
+ // If flattened is not an object (should be rare for a top-level schema), wrap it
136
+ base = { const: flattened };
137
+ }
138
+ const output = {
139
+ $schema: "https://json-schema.org/draft/2020-12/schema",
140
+ ...(topLevelId ? { $id: topLevelId } : {}),
141
+ ...base,
142
+ };
143
+ // Merge collected defs into output.$defs, taking care not to clobber any existing
144
+ if (!("$defs" in output))
145
+ output.$defs = {};
146
+ const finalDefs = output.$defs || {};
147
+ for (const [k, v] of Object.entries(outDefs)) {
148
+ if (!(k in finalDefs))
149
+ finalDefs[k] = v;
150
+ }
151
+ output.$defs = finalDefs;
152
+ // Ensure a stable order for readability
153
+ const ordered = orderKeys(output, ["$id", "$schema", "$vocabulary", "$defs", "title", "description", "type", "allOf", "anyOf", "oneOf", "not", "if", "then", "else", "properties", "required", "additionalProperties", "unevaluatedProperties"]);
154
+ fs.mkdirSync(path.dirname(outPath), { recursive: true });
155
+ fs.writeFileSync(outPath, JSON.stringify(ordered, null, 4), "utf8");
156
+ console.log(`Wrote flattened schema to ${outPath}`);
157
+ }
158
+ function orderKeys(obj, preferred) {
159
+ if (Array.isArray(obj))
160
+ return obj.map((v) => orderKeys(v, preferred));
161
+ if (!obj || typeof obj !== "object")
162
+ return obj;
163
+ const keys = Object.keys(obj);
164
+ const sorted = [
165
+ ...preferred.filter((k) => keys.includes(k)),
166
+ ...keys.filter((k) => !preferred.includes(k)).sort()
167
+ ];
168
+ const out = {};
169
+ for (const k of sorted)
170
+ out[k] = orderKeys(obj[k], preferred);
171
+ return out;
172
+ }
173
+ main();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,139 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * Generic extractor: given a subschema name that exists under Genesis.json $defs,
5
+ * produce a standalone JSON Schema file that contains that subschema plus an inner $defs
6
+ * object holding all direct & transitive local $defs dependencies (by #/$defs/... $ref).
7
+ *
8
+ * Genesis.json itself is left unchanged.
9
+ *
10
+ * Usage:
11
+ * node ./dist/scripts/extractSubschemaWithDefs.js --name <DefName>
12
+ *
13
+ * Writes: src/schemas/<DefName>.json
14
+ */
15
+ async function main() {
16
+ const { name } = parseArgs(process.argv.slice(2));
17
+ if (!name) {
18
+ console.error('Missing --name <DefName> argument');
19
+ process.exit(1);
20
+ }
21
+ const projectRoot = process.cwd();
22
+ const schemasDir = path.join(projectRoot, 'src', 'schemas');
23
+ const genesisPath = path.join(schemasDir, 'Genesis.json');
24
+ const outPath = path.join(schemasDir, `${name}.json`);
25
+ if (!fs.existsSync(genesisPath)) {
26
+ console.error(`Genesis.json not found at ${genesisPath}`);
27
+ process.exit(1);
28
+ }
29
+ const raw = fs.readFileSync(genesisPath, 'utf-8');
30
+ const genesis = JSON.parse(raw);
31
+ const rootDefs = genesis.$defs;
32
+ if (!rootDefs || typeof rootDefs !== 'object') {
33
+ console.error('No $defs object found in Genesis.json');
34
+ process.exit(1);
35
+ }
36
+ const target = rootDefs[name];
37
+ if (!target) {
38
+ console.error(`Subschema named '${name}' not found under $defs in Genesis.json`);
39
+ process.exit(1);
40
+ }
41
+ // Collect transitive local $defs names referenced by target
42
+ const needed = collectLocalDefClosure(target, rootDefs);
43
+ // Build output schema: clone target and attach collected subset as $defs
44
+ const targetClone = deepClone(target);
45
+ const defsOut = {};
46
+ for (const defName of needed) {
47
+ // Avoid including the target itself inside its own $defs (mirrors previous pattern)
48
+ if (defName === name)
49
+ continue;
50
+ const defSchema = rootDefs[defName];
51
+ if (defSchema === undefined) {
52
+ console.error(`Warning: referenced def '${defName}' missing in root $defs (skipped).`);
53
+ continue;
54
+ }
55
+ defsOut[defName] = deepClone(defSchema);
56
+ }
57
+ // Merge any pre-existing inner $defs of targetClone (if present) giving precedence to collected ones
58
+ const existingInner = isObject(targetClone.$defs) ? targetClone.$defs : {};
59
+ targetClone.$defs = { ...existingInner, ...defsOut };
60
+ fs.writeFileSync(outPath, JSON.stringify(targetClone, null, 2) + '\n');
61
+ console.log(`Extracted subschema '${name}' with ${needed.size} transitive local defs -> ${outPath}`);
62
+ }
63
+ // ---- Helpers ----
64
+ function parseArgs(args) {
65
+ let name;
66
+ for (let i = 0; i < args.length; i++) {
67
+ const a = args[i];
68
+ if (a === '--name') {
69
+ name = args[i + 1];
70
+ i++;
71
+ }
72
+ else if (a.startsWith('--name=')) {
73
+ name = a.split('=')[1];
74
+ }
75
+ }
76
+ return { name };
77
+ }
78
+ function isObject(v) {
79
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
80
+ }
81
+ function deepClone(v) {
82
+ if (Array.isArray(v))
83
+ return v.map((x) => deepClone(x));
84
+ if (isObject(v)) {
85
+ const out = {};
86
+ for (const k of Object.keys(v))
87
+ out[k] = deepClone(v[k]);
88
+ return out;
89
+ }
90
+ return v;
91
+ }
92
+ function extractLocalDefName(ref) {
93
+ // Accept refs like '#/$defs/Name' only (single-level under $defs)
94
+ if (!ref || !ref.startsWith('#/'))
95
+ return null;
96
+ const parts = ref.slice(2).split('/'); // remove '#/'
97
+ if (parts.length !== 2)
98
+ return null;
99
+ if (parts[0] !== '$defs')
100
+ return null;
101
+ // Decode JSON Pointer tokens for the def name
102
+ const name = parts[1].replace(/~1/g, '/').replace(/~0/g, '~');
103
+ return name;
104
+ }
105
+ function collectLocalDefClosure(node, rootDefs) {
106
+ const needed = new Set();
107
+ const queue = [];
108
+ function visit(n) {
109
+ if (Array.isArray(n)) {
110
+ for (const item of n)
111
+ visit(item);
112
+ return;
113
+ }
114
+ if (!isObject(n))
115
+ return;
116
+ if (typeof n.$ref === 'string') {
117
+ const name = extractLocalDefName(n.$ref);
118
+ if (name && !needed.has(name)) {
119
+ needed.add(name);
120
+ queue.push(name);
121
+ }
122
+ }
123
+ for (const val of Object.values(n))
124
+ visit(val);
125
+ }
126
+ visit(node);
127
+ while (queue.length > 0) {
128
+ const name = queue.shift();
129
+ const def = rootDefs[name];
130
+ if (!def)
131
+ continue; // Missing def handled earlier
132
+ visit(def);
133
+ }
134
+ return needed;
135
+ }
136
+ main().catch((e) => {
137
+ console.error(e);
138
+ process.exit(1);
139
+ });
@@ -0,0 +1 @@
1
+ export {};