t44 0.2.0-rc.1
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.
Potentially problematic release.
This version of t44 might be problematic. Click here for more details.
- package/LICENSE.md +203 -0
- package/README.md +154 -0
- package/bin/activate +36 -0
- package/bin/activate.ts +30 -0
- package/bin/postinstall.sh +19 -0
- package/bin/shell +27 -0
- package/bin/t44 +27 -0
- package/caps/HomeRegistry.v0.ts +298 -0
- package/caps/OpenApiSchema.v0.ts +192 -0
- package/caps/ProjectDeployment.v0.ts +363 -0
- package/caps/ProjectDevelopment.v0.ts +246 -0
- package/caps/ProjectPublishing.v0.ts +307 -0
- package/caps/ProjectRack.v0.ts +128 -0
- package/caps/WorkspaceCli.v0.ts +391 -0
- package/caps/WorkspaceConfig.v0.ts +626 -0
- package/caps/WorkspaceConfig.yaml +53 -0
- package/caps/WorkspaceConnection.v0.ts +240 -0
- package/caps/WorkspaceEntityConfig.v0.ts +64 -0
- package/caps/WorkspaceEntityFact.v0.ts +193 -0
- package/caps/WorkspaceInfo.v0.ts +554 -0
- package/caps/WorkspaceInit.v0.ts +30 -0
- package/caps/WorkspaceKey.v0.ts +186 -0
- package/caps/WorkspaceProjects.v0.ts +455 -0
- package/caps/WorkspacePrompt.v0.ts +396 -0
- package/caps/WorkspaceShell.sh +39 -0
- package/caps/WorkspaceShell.v0.ts +104 -0
- package/caps/WorkspaceShell.yaml +65 -0
- package/caps/WorkspaceShellCli.v0.ts +109 -0
- package/caps/WorkspaceTest.v0.ts +167 -0
- package/caps/providers/LICENSE.md +8 -0
- package/caps/providers/README.md +2 -0
- package/caps/providers/bunny.net/ProjectDeployment.v0.ts +328 -0
- package/caps/providers/bunny.net/api-pull.v0.test.ts +319 -0
- package/caps/providers/bunny.net/api-pull.v0.ts +161 -0
- package/caps/providers/bunny.net/api-storage.v0.test.ts +168 -0
- package/caps/providers/bunny.net/api-storage.v0.ts +245 -0
- package/caps/providers/bunny.net/api.v0.ts +95 -0
- package/caps/providers/dynadot.com/ProjectDeployment.v0.ts +207 -0
- package/caps/providers/dynadot.com/api-domains.v0.test.ts +147 -0
- package/caps/providers/dynadot.com/api-domains.v0.ts +137 -0
- package/caps/providers/dynadot.com/api.v0.ts +88 -0
- package/caps/providers/git-scm.com/ProjectPublishing.v0.ts +231 -0
- package/caps/providers/github.com/ProjectPublishing.v0.ts +75 -0
- package/caps/providers/github.com/api.v0.ts +90 -0
- package/caps/providers/npmjs.com/ProjectPublishing.v0.ts +741 -0
- package/caps/providers/vercel.com/ProjectDeployment.v0.ts +339 -0
- package/caps/providers/vercel.com/api.v0.test.ts +67 -0
- package/caps/providers/vercel.com/api.v0.ts +132 -0
- package/caps/providers/vercel.com/bun.lock +194 -0
- package/caps/providers/vercel.com/package.json +10 -0
- package/caps/providers/vercel.com/project.v0.test.ts +108 -0
- package/caps/providers/vercel.com/project.v0.ts +150 -0
- package/caps/providers/vercel.com/tsconfig.json +28 -0
- package/docs/Overview.drawio +189 -0
- package/docs/Overview.svg +4 -0
- package/lib/crypto.ts +53 -0
- package/lib/openapi.ts +132 -0
- package/lib/ucan.ts +137 -0
- package/package.json +41 -0
- package/structs/HomeRegistryConfig.v0.ts +27 -0
- package/structs/ProjectDeploymentConfig.v0.ts +27 -0
- package/structs/ProjectDeploymentFact.v0.ts +110 -0
- package/structs/ProjectPublishingFact.v0.ts +69 -0
- package/structs/ProjectRackConfig.v0.ts +27 -0
- package/structs/WorkspaceCliConfig.v0.ts +27 -0
- package/structs/WorkspaceConfig.v0.ts +27 -0
- package/structs/WorkspaceKeyConfig.v0.ts +27 -0
- package/structs/WorkspaceMappings.v0.ts +27 -0
- package/structs/WorkspaceProjectsConfig.v0.ts +27 -0
- package/structs/WorkspaceRepositories.v0.ts +27 -0
- package/structs/WorkspaceShellConfig.v0.ts +45 -0
- package/structs/providers/LICENSE.md +8 -0
- package/structs/providers/README.md +2 -0
- package/structs/providers/bunny.net/ProjectDeploymentFact.v0.ts +41 -0
- package/structs/providers/bunny.net/WorkspaceConnectionConfig.v0.ts +42 -0
- package/structs/providers/dynadot.com/DomainFact.v0.ts +146 -0
- package/structs/providers/dynadot.com/WorkspaceConnectionConfig.v0.ts +41 -0
- package/structs/providers/git-scm.com/ProjectPublishingFact.v0.ts +46 -0
- package/structs/providers/github.com/ProjectPublishingFact.v0.ts +52 -0
- package/structs/providers/github.com/WorkspaceConnectionConfig.v0.ts +42 -0
- package/structs/providers/npmjs.com/ProjectPublishingFact.v0.ts +48 -0
- package/structs/providers/vercel.com/ProjectDeploymentFact.v0.ts +38 -0
- package/structs/providers/vercel.com/WorkspaceConnectionConfig.v0.ts +48 -0
- package/tsconfig.json +28 -0
- package/workspace-rt.ts +134 -0
- package/workspace.yaml +5 -0
package/lib/crypto.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
import * as crypto from 'crypto'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Encrypt a string using AES-256-GCM with a key derived from the private key
|
|
6
|
+
*/
|
|
7
|
+
export function encryptString(plaintext: string, privateKeyBase64: string): string {
|
|
8
|
+
// Derive a 32-byte symmetric key from the private key using SHA-256
|
|
9
|
+
const keyBytes = Buffer.from(privateKeyBase64, 'base64')
|
|
10
|
+
const symmetricKey = crypto.createHash('sha256').update(keyBytes).digest()
|
|
11
|
+
|
|
12
|
+
// Generate a random IV
|
|
13
|
+
const iv = crypto.randomBytes(16)
|
|
14
|
+
|
|
15
|
+
// Encrypt using AES-256-GCM
|
|
16
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', symmetricKey, iv)
|
|
17
|
+
const encrypted = Buffer.concat([
|
|
18
|
+
cipher.update(plaintext, 'utf8'),
|
|
19
|
+
cipher.final()
|
|
20
|
+
])
|
|
21
|
+
const authTag = cipher.getAuthTag()
|
|
22
|
+
|
|
23
|
+
// Combine IV + authTag + encrypted data and encode as base64
|
|
24
|
+
const combined = Buffer.concat([iv, authTag, encrypted])
|
|
25
|
+
return combined.toString('base64')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Decrypt a string using AES-256-GCM with a key derived from the private key
|
|
30
|
+
*/
|
|
31
|
+
export function decryptString(ciphertext: string, privateKeyBase64: string): string {
|
|
32
|
+
// Derive the same symmetric key from the private key
|
|
33
|
+
const keyBytes = Buffer.from(privateKeyBase64, 'base64')
|
|
34
|
+
const symmetricKey = crypto.createHash('sha256').update(keyBytes).digest()
|
|
35
|
+
|
|
36
|
+
// Decode the combined data
|
|
37
|
+
const combined = Buffer.from(ciphertext, 'base64')
|
|
38
|
+
|
|
39
|
+
// Extract IV (16 bytes), authTag (16 bytes), and encrypted data
|
|
40
|
+
const iv = combined.subarray(0, 16)
|
|
41
|
+
const authTag = combined.subarray(16, 32)
|
|
42
|
+
const encrypted = combined.subarray(32)
|
|
43
|
+
|
|
44
|
+
// Decrypt using AES-256-GCM
|
|
45
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', symmetricKey, iv)
|
|
46
|
+
decipher.setAuthTag(authTag)
|
|
47
|
+
const decrypted = Buffer.concat([
|
|
48
|
+
decipher.update(encrypted),
|
|
49
|
+
decipher.final()
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
return decrypted.toString('utf8')
|
|
53
|
+
}
|
package/lib/openapi.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
|
|
2
|
+
import Ajv from 'ajv'
|
|
3
|
+
import addFormats from 'ajv-formats'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert OpenAPI schema to JSON Schema compatible format
|
|
7
|
+
*/
|
|
8
|
+
export function convertOpenApiToJsonSchema(obj: any, root: any, warnings: any[] = [], visited = new WeakSet()): any {
|
|
9
|
+
if (typeof obj !== 'object' || obj === null) return obj
|
|
10
|
+
if (visited.has(obj)) return obj
|
|
11
|
+
visited.add(obj)
|
|
12
|
+
|
|
13
|
+
if (obj.$ref) {
|
|
14
|
+
const refPath = obj.$ref.replace(/^#\//, '').split('/')
|
|
15
|
+
let resolved = root
|
|
16
|
+
for (const part of refPath) {
|
|
17
|
+
const decodedPart = part.replace(/~1/g, '/').replace(/~0/g, '~')
|
|
18
|
+
resolved = resolved?.[decodedPart]
|
|
19
|
+
if (!resolved) {
|
|
20
|
+
warnings.push({
|
|
21
|
+
type: 'unresolved_reference',
|
|
22
|
+
message: `Cannot resolve reference ${obj.$ref}, using permissive schema`,
|
|
23
|
+
ref: obj.$ref
|
|
24
|
+
})
|
|
25
|
+
return {}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return convertOpenApiToJsonSchema(resolved, root, warnings, visited)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const result: any = Array.isArray(obj) ? [] : {}
|
|
32
|
+
for (const key in obj) {
|
|
33
|
+
if (key === 'nullable' && obj.nullable === true) {
|
|
34
|
+
if (obj.type) {
|
|
35
|
+
result.type = Array.isArray(obj.type) ? [...obj.type, 'null'] : [obj.type, 'null']
|
|
36
|
+
} else {
|
|
37
|
+
result.type = 'null'
|
|
38
|
+
}
|
|
39
|
+
} else if (key === 'example' || key === 'discriminator') {
|
|
40
|
+
continue
|
|
41
|
+
} else {
|
|
42
|
+
result[key] = convertOpenApiToJsonSchema(obj[key], root, warnings, visited)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return result
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a configured AJV instance for OpenAPI/JSON Schema validation
|
|
50
|
+
*/
|
|
51
|
+
export function createAjvInstance(): Ajv {
|
|
52
|
+
const ajv = new Ajv({
|
|
53
|
+
allErrors: true,
|
|
54
|
+
strict: false,
|
|
55
|
+
validateFormats: true,
|
|
56
|
+
logger: false
|
|
57
|
+
})
|
|
58
|
+
addFormats(ajv)
|
|
59
|
+
return ajv
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Validate data against a JSON Schema
|
|
64
|
+
*/
|
|
65
|
+
export function validateWithSchema(
|
|
66
|
+
schema: any,
|
|
67
|
+
data: any,
|
|
68
|
+
ajv?: Ajv
|
|
69
|
+
): { valid: boolean; errors: any[] } {
|
|
70
|
+
const validator = ajv || createAjvInstance()
|
|
71
|
+
|
|
72
|
+
let validate
|
|
73
|
+
try {
|
|
74
|
+
validate = validator.compile(schema)
|
|
75
|
+
} catch (error: any) {
|
|
76
|
+
return {
|
|
77
|
+
valid: false,
|
|
78
|
+
errors: [{
|
|
79
|
+
type: 'schema_compilation_failed',
|
|
80
|
+
message: `Schema compilation failed: ${error.message}`,
|
|
81
|
+
error: error.message
|
|
82
|
+
}]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!validate(data)) {
|
|
87
|
+
const validationErrors = validate.errors?.map(err => ({
|
|
88
|
+
path: err.instancePath || '/',
|
|
89
|
+
message: err.message,
|
|
90
|
+
params: err.params,
|
|
91
|
+
keyword: err.keyword,
|
|
92
|
+
schemaPath: err.schemaPath
|
|
93
|
+
})) || []
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
valid: false,
|
|
97
|
+
errors: validationErrors
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { valid: true, errors: [] }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Validate a single value against a property schema
|
|
106
|
+
*/
|
|
107
|
+
export function validatePropertyValue(
|
|
108
|
+
propertySchema: any,
|
|
109
|
+
value: any,
|
|
110
|
+
propertyName: string
|
|
111
|
+
): { valid: boolean; error?: string } {
|
|
112
|
+
// Build a minimal schema for the single property
|
|
113
|
+
const schema = {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: {
|
|
116
|
+
[propertyName]: propertySchema
|
|
117
|
+
},
|
|
118
|
+
required: [propertyName]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const result = validateWithSchema(schema, { [propertyName]: value })
|
|
122
|
+
|
|
123
|
+
if (!result.valid && result.errors.length > 0) {
|
|
124
|
+
const error = result.errors[0]
|
|
125
|
+
return {
|
|
126
|
+
valid: false,
|
|
127
|
+
error: error.message || `Invalid value for ${propertyName}`
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return { valid: true }
|
|
132
|
+
}
|
package/lib/ucan.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
|
|
2
|
+
import { ed25519 } from '@ucanto/principal';
|
|
3
|
+
import * as Server from '@ucanto/server';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export async function generateKeypair(): Promise<{ did: string; privateKey: string }> {
|
|
7
|
+
const principal = await ed25519.generate();
|
|
8
|
+
// The principal itself is a Uint8Array containing the private key
|
|
9
|
+
const privateKeyBytes = new Uint8Array(principal as any);
|
|
10
|
+
return {
|
|
11
|
+
did: principal.did(),
|
|
12
|
+
privateKey: Buffer.from(privateKeyBytes).toString('base64'),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Extract DID from a base64-encoded private key
|
|
18
|
+
* @param privateKeyBase64 - Base64-encoded private key
|
|
19
|
+
* @returns The DID string
|
|
20
|
+
*/
|
|
21
|
+
export function didForPrivateKey(privateKeyBase64: string): string {
|
|
22
|
+
const keyBytes = Buffer.from(privateKeyBase64, 'base64');
|
|
23
|
+
const principal = ed25519.decode(new Uint8Array(keyBytes));
|
|
24
|
+
return principal.did();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Issue a UCAN capability delegation
|
|
29
|
+
* @param options.issuerPrivateKey - Base64-encoded private key of the issuer
|
|
30
|
+
* @param options.audienceDID - DID of the audience (recipient)
|
|
31
|
+
* @param options.capabilities - Array of capabilities to delegate
|
|
32
|
+
* @param options.expiresIn - Expiration time in seconds from now (default: 1 year)
|
|
33
|
+
* @returns Base64-encoded UCAN token
|
|
34
|
+
*/
|
|
35
|
+
export async function issueCapability(options: {
|
|
36
|
+
issuerPrivateKey: string;
|
|
37
|
+
audienceDID: string;
|
|
38
|
+
capabilities: Array<{ with: string; can: string }>;
|
|
39
|
+
expiresIn?: number;
|
|
40
|
+
}): Promise<string> {
|
|
41
|
+
// Decode the issuer's private key
|
|
42
|
+
const keyBytes = Buffer.from(options.issuerPrivateKey, 'base64');
|
|
43
|
+
const issuer = ed25519.decode(new Uint8Array(keyBytes));
|
|
44
|
+
|
|
45
|
+
// Parse the audience DID
|
|
46
|
+
const audience = ed25519.Verifier.parse(options.audienceDID);
|
|
47
|
+
|
|
48
|
+
const expiresIn = options.expiresIn || 365 * 24 * 60 * 60; // 1 year
|
|
49
|
+
const expiration = Math.floor(Date.now() / 1000) + expiresIn;
|
|
50
|
+
|
|
51
|
+
const delegation = await Server.delegate({
|
|
52
|
+
issuer,
|
|
53
|
+
audience,
|
|
54
|
+
capabilities: options.capabilities,
|
|
55
|
+
expiration,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const archive = await delegation.archive();
|
|
59
|
+
if (!archive.ok) {
|
|
60
|
+
throw new Error('Failed to archive delegation');
|
|
61
|
+
}
|
|
62
|
+
return Buffer.from(archive.ok).toString('base64');
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Validate a UCAN capability delegation
|
|
67
|
+
* @param options.ucanToken - Base64-encoded UCAN token
|
|
68
|
+
* @param options.issuerDID - Expected DID of the issuer
|
|
69
|
+
* @param options.expectedCapability - Expected capability (optional)
|
|
70
|
+
* @returns Validation result with delegation details
|
|
71
|
+
*/
|
|
72
|
+
export async function validateCapability(options: {
|
|
73
|
+
ucanToken: string;
|
|
74
|
+
issuerDID: string;
|
|
75
|
+
expectedCapability?: { can: string };
|
|
76
|
+
}): Promise<{
|
|
77
|
+
valid: boolean;
|
|
78
|
+
error?: string;
|
|
79
|
+
issuer?: string;
|
|
80
|
+
audience?: string;
|
|
81
|
+
capabilities?: Array<{ with: string; can: string }>;
|
|
82
|
+
expiration?: number;
|
|
83
|
+
}> {
|
|
84
|
+
try {
|
|
85
|
+
// Parse the UCAN from the token
|
|
86
|
+
const carBytes = Buffer.from(options.ucanToken, 'base64');
|
|
87
|
+
const result: any = await Server.Delegation.extract(carBytes);
|
|
88
|
+
if (!result.ok) {
|
|
89
|
+
return {
|
|
90
|
+
valid: false,
|
|
91
|
+
error: `Failed to parse UCAN: ${result.error.message}`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const delegation: any = result.ok;
|
|
95
|
+
|
|
96
|
+
// Basic validation: check expiration
|
|
97
|
+
const now = Math.floor(Date.now() / 1000);
|
|
98
|
+
if (delegation.expiration && delegation.expiration < now) {
|
|
99
|
+
return {
|
|
100
|
+
valid: false,
|
|
101
|
+
error: 'UCAN has expired',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Verify issuer matches expected
|
|
106
|
+
if (delegation.issuer.did() !== options.issuerDID) {
|
|
107
|
+
return {
|
|
108
|
+
valid: false,
|
|
109
|
+
error: `UCAN not issued by expected issuer. Expected: ${options.issuerDID}, Got: ${delegation.issuer.did()}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Validate capability if specified
|
|
114
|
+
if (options.expectedCapability) {
|
|
115
|
+
const capability = delegation.capabilities[0];
|
|
116
|
+
if (capability.can !== options.expectedCapability.can) {
|
|
117
|
+
return {
|
|
118
|
+
valid: false,
|
|
119
|
+
error: `Invalid capability: expected '${options.expectedCapability.can}', got '${capability.can}'`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
valid: true,
|
|
126
|
+
issuer: delegation.issuer.did(),
|
|
127
|
+
audience: delegation.audience.did(),
|
|
128
|
+
capabilities: delegation.capabilities,
|
|
129
|
+
expiration: delegation.expiration,
|
|
130
|
+
};
|
|
131
|
+
} catch (error: any) {
|
|
132
|
+
return {
|
|
133
|
+
valid: false,
|
|
134
|
+
error: `Failed to validate UCAN: ${error.message}`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "t44",
|
|
3
|
+
"version": "0.2.0-rc.1",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/Stream44/t44.git"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"bin": {
|
|
11
|
+
"t44": "./bin/t44"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
"./caps/WorkspaceConfig.v0": "./caps/WorkspaceConfig.v0.ts"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"js-yaml": "^4.1.0",
|
|
18
|
+
"commander": "^14.0.0",
|
|
19
|
+
"chalk": "^5.6.2",
|
|
20
|
+
"dotenv": "^17.2.3",
|
|
21
|
+
"fast-glob": "^3.3.3",
|
|
22
|
+
"inquirer": "^12.4.0",
|
|
23
|
+
"@ucanto/principal": "^9.0.3",
|
|
24
|
+
"@ucanto/server": "^11.0.3",
|
|
25
|
+
"t44": "^0.2.0-rc.1",
|
|
26
|
+
"@stream44.studio/encapsulate": "^0.2.0-rc.5"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/bun": "^1.3.4",
|
|
30
|
+
"@types/node": "^25.0.3",
|
|
31
|
+
"@types/js-yaml": "^4.0.9",
|
|
32
|
+
"bun-types": "^1.3.4",
|
|
33
|
+
"upload-to-bunny": "^2.1.0",
|
|
34
|
+
"axios": "^1.13.4",
|
|
35
|
+
"vercel": "^50.4.9",
|
|
36
|
+
"turbo": "^2.7.5"
|
|
37
|
+
},
|
|
38
|
+
"workspaces": [
|
|
39
|
+
"caps/providers/vercel.com"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#': {
|
|
10
|
+
capsuleName: {
|
|
11
|
+
type: CapsulePropertyTypes.Literal,
|
|
12
|
+
value: capsule['#']
|
|
13
|
+
},
|
|
14
|
+
schema: {
|
|
15
|
+
type: CapsulePropertyTypes.Literal,
|
|
16
|
+
value: {}
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}, {
|
|
21
|
+
extendsCapsule: 't44/caps/WorkspaceEntityConfig.v0',
|
|
22
|
+
importMeta: import.meta,
|
|
23
|
+
importStack: makeImportStack(),
|
|
24
|
+
capsuleName: capsule['#'],
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
capsule['#'] = 't44/structs/HomeRegistryConfig.v0'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#': {
|
|
10
|
+
capsuleName: {
|
|
11
|
+
type: CapsulePropertyTypes.Literal,
|
|
12
|
+
value: capsule['#']
|
|
13
|
+
},
|
|
14
|
+
schema: {
|
|
15
|
+
type: CapsulePropertyTypes.Literal,
|
|
16
|
+
value: {}
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}, {
|
|
21
|
+
extendsCapsule: 't44/caps/WorkspaceEntityConfig.v0',
|
|
22
|
+
importMeta: import.meta,
|
|
23
|
+
importStack: makeImportStack(),
|
|
24
|
+
capsuleName: capsule['#'],
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
capsule['#'] = 't44/structs/ProjectDeploymentConfig.v0'
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#t44/caps/OpenApiSchema.v0': {
|
|
10
|
+
as: 'schema',
|
|
11
|
+
options: {
|
|
12
|
+
'#': {
|
|
13
|
+
definitions: {
|
|
14
|
+
'ProjectDeploymentStatus': {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
projectName: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'The name of the deployed project'
|
|
20
|
+
},
|
|
21
|
+
provider: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'The deployment provider (e.g., vercel.com, bunny.net)'
|
|
24
|
+
},
|
|
25
|
+
status: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
enum: ['READY', 'BUILDING', 'ERROR', 'DISABLED', 'UNKNOWN'],
|
|
28
|
+
description: 'Current deployment status'
|
|
29
|
+
},
|
|
30
|
+
publicUrl: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
format: 'uri',
|
|
33
|
+
description: 'The public URL where the deployment is accessible'
|
|
34
|
+
},
|
|
35
|
+
createdAt: {
|
|
36
|
+
type: 'integer',
|
|
37
|
+
description: 'Timestamp when the deployment was created'
|
|
38
|
+
},
|
|
39
|
+
updatedAt: {
|
|
40
|
+
type: 'integer',
|
|
41
|
+
description: 'Timestamp when the deployment was last updated'
|
|
42
|
+
},
|
|
43
|
+
providerProjectId: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Provider-specific project identifier'
|
|
46
|
+
},
|
|
47
|
+
providerPortalUrl: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
format: 'uri',
|
|
50
|
+
description: 'URL to the provider admin portal for this deployment'
|
|
51
|
+
},
|
|
52
|
+
usage: {
|
|
53
|
+
type: 'object',
|
|
54
|
+
properties: {
|
|
55
|
+
storageBytes: {
|
|
56
|
+
type: 'integer',
|
|
57
|
+
description: 'Storage used in bytes'
|
|
58
|
+
},
|
|
59
|
+
filesCount: {
|
|
60
|
+
type: 'integer',
|
|
61
|
+
description: 'Number of files stored'
|
|
62
|
+
},
|
|
63
|
+
bandwidthBytes: {
|
|
64
|
+
type: 'integer',
|
|
65
|
+
description: 'Bandwidth used in bytes (monthly)'
|
|
66
|
+
},
|
|
67
|
+
charges: {
|
|
68
|
+
type: 'number',
|
|
69
|
+
description: 'Monthly charges in USD'
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
description: 'Usage statistics for the deployment'
|
|
73
|
+
},
|
|
74
|
+
error: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
description: 'Error message if status retrieval failed'
|
|
77
|
+
},
|
|
78
|
+
rawDefinitionFilepaths: {
|
|
79
|
+
type: 'array',
|
|
80
|
+
items: {
|
|
81
|
+
type: 'string'
|
|
82
|
+
},
|
|
83
|
+
description: 'Relative filepaths to the raw provider-specific definition files'
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
required: ['projectName', 'provider', 'rawDefinitionFilepaths']
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
'#': {
|
|
93
|
+
capsuleName: {
|
|
94
|
+
type: CapsulePropertyTypes.Literal,
|
|
95
|
+
value: capsule['#']
|
|
96
|
+
},
|
|
97
|
+
origin: {
|
|
98
|
+
type: CapsulePropertyTypes.Literal,
|
|
99
|
+
value: 'workspace.foundation'
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}, {
|
|
104
|
+
extendsCapsule: 't44/caps/WorkspaceEntityFact.v0',
|
|
105
|
+
importMeta: import.meta,
|
|
106
|
+
importStack: makeImportStack(),
|
|
107
|
+
capsuleName: capsule['#'],
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
capsule['#'] = 't44/structs/ProjectDeploymentFact.v0'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#t44/caps/OpenApiSchema.v0': {
|
|
10
|
+
as: 'schema',
|
|
11
|
+
options: {
|
|
12
|
+
'#': {
|
|
13
|
+
definitions: {
|
|
14
|
+
'ProjectPublishingStatus': {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
projectName: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'The name of the published project'
|
|
20
|
+
},
|
|
21
|
+
provider: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'The publishing provider (e.g., github.com, git-scm.com, npmjs.com)'
|
|
24
|
+
},
|
|
25
|
+
status: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
enum: ['READY', 'PUBLISHED', 'ERROR', 'SKIPPED', 'UNKNOWN'],
|
|
28
|
+
description: 'Current publishing status'
|
|
29
|
+
},
|
|
30
|
+
publicUrl: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
format: 'uri',
|
|
33
|
+
description: 'The public URL where the published resource is accessible'
|
|
34
|
+
},
|
|
35
|
+
updatedAt: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
format: 'date-time',
|
|
38
|
+
description: 'Timestamp when the publishing was last updated'
|
|
39
|
+
},
|
|
40
|
+
error: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
description: 'Error message if publishing failed'
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
required: ['projectName', 'provider']
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
'#': {
|
|
52
|
+
capsuleName: {
|
|
53
|
+
type: CapsulePropertyTypes.Literal,
|
|
54
|
+
value: capsule['#']
|
|
55
|
+
},
|
|
56
|
+
origin: {
|
|
57
|
+
type: CapsulePropertyTypes.Literal,
|
|
58
|
+
value: 'workspace.foundation'
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}, {
|
|
63
|
+
extendsCapsule: 't44/caps/WorkspaceEntityFact.v0',
|
|
64
|
+
importMeta: import.meta,
|
|
65
|
+
importStack: makeImportStack(),
|
|
66
|
+
capsuleName: capsule['#'],
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
capsule['#'] = 't44/structs/ProjectPublishingFact.v0'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#': {
|
|
10
|
+
capsuleName: {
|
|
11
|
+
type: CapsulePropertyTypes.Literal,
|
|
12
|
+
value: capsule['#']
|
|
13
|
+
},
|
|
14
|
+
schema: {
|
|
15
|
+
type: CapsulePropertyTypes.Literal,
|
|
16
|
+
value: {}
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}, {
|
|
21
|
+
extendsCapsule: 't44/caps/WorkspaceEntityConfig.v0',
|
|
22
|
+
importMeta: import.meta,
|
|
23
|
+
importStack: makeImportStack(),
|
|
24
|
+
capsuleName: capsule['#'],
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
capsule['#'] = 't44/structs/ProjectRackConfig.v0'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#': {
|
|
10
|
+
capsuleName: {
|
|
11
|
+
type: CapsulePropertyTypes.Literal,
|
|
12
|
+
value: capsule['#']
|
|
13
|
+
},
|
|
14
|
+
schema: {
|
|
15
|
+
type: CapsulePropertyTypes.Literal,
|
|
16
|
+
value: {}
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}, {
|
|
21
|
+
extendsCapsule: 't44/caps/WorkspaceEntityConfig.v0',
|
|
22
|
+
importMeta: import.meta,
|
|
23
|
+
importStack: makeImportStack(),
|
|
24
|
+
capsuleName: capsule['#'],
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
capsule['#'] = 't44/structs/WorkspaceCliConfig.v0'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#': {
|
|
10
|
+
capsuleName: {
|
|
11
|
+
type: CapsulePropertyTypes.Literal,
|
|
12
|
+
value: capsule['#']
|
|
13
|
+
},
|
|
14
|
+
schema: {
|
|
15
|
+
type: CapsulePropertyTypes.Literal,
|
|
16
|
+
value: {}
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}, {
|
|
21
|
+
extendsCapsule: 't44/caps/WorkspaceEntityConfig.v0',
|
|
22
|
+
importMeta: import.meta,
|
|
23
|
+
importStack: makeImportStack(),
|
|
24
|
+
capsuleName: capsule['#'],
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
capsule['#'] = 't44/structs/WorkspaceConfig.v0'
|