@superblocksteam/shared 0.9607.3 → 0.9608.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.
- package/dist/database-lifecycle/appDatabaseCompatibility.d.ts +49 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.d.ts.map +1 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.js +32 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.js.map +1 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.test.d.ts +2 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.test.d.ts.map +1 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.test.js +47 -0
- package/dist/database-lifecycle/appDatabaseCompatibility.test.js.map +1 -0
- package/dist/database-lifecycle/destructiveMigrations.d.ts +12 -0
- package/dist/database-lifecycle/destructiveMigrations.d.ts.map +1 -1
- package/dist/database-lifecycle/destructiveMigrations.js +114 -0
- package/dist/database-lifecycle/destructiveMigrations.js.map +1 -1
- package/dist/database-lifecycle/destructiveMigrations.test.js +79 -0
- package/dist/database-lifecycle/destructiveMigrations.test.js.map +1 -1
- package/dist/database-lifecycle/index.d.ts +46 -2
- package/dist/database-lifecycle/index.d.ts.map +1 -1
- package/dist/database-lifecycle/index.js +127 -1
- package/dist/database-lifecycle/index.js.map +1 -1
- package/dist/database-lifecycle/providerDiagnostics.test.d.ts +2 -0
- package/dist/database-lifecycle/providerDiagnostics.test.d.ts.map +1 -0
- package/dist/database-lifecycle/providerDiagnostics.test.js +119 -0
- package/dist/database-lifecycle/providerDiagnostics.test.js.map +1 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.d.ts +65 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.d.ts.map +1 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.js +87 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.js.map +1 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.test.d.ts +2 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.test.d.ts.map +1 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.test.js +285 -0
- package/dist/environment-compatibility/appEnvironmentCompatibility.test.js.map +1 -0
- package/dist/errors/http.d.ts +15 -4
- package/dist/errors/http.d.ts.map +1 -1
- package/dist/errors/http.js +25 -7
- package/dist/errors/http.js.map +1 -1
- package/dist/errors/http.test.d.ts +2 -0
- package/dist/errors/http.test.d.ts.map +1 -0
- package/dist/errors/http.test.js +28 -0
- package/dist/errors/http.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/plugins/templates/restApiIntegration.d.ts.map +1 -1
- package/dist/plugins/templates/restApiIntegration.js +2 -0
- package/dist/plugins/templates/restApiIntegration.js.map +1 -1
- package/dist/plugins/templates/shared/auth.d.ts +3 -1
- package/dist/plugins/templates/shared/auth.d.ts.map +1 -1
- package/dist/plugins/templates/shared/auth.js +129 -17
- package/dist/plugins/templates/shared/auth.js.map +1 -1
- package/dist/plugins/templates/shared/auth.test.d.ts +2 -0
- package/dist/plugins/templates/shared/auth.test.d.ts.map +1 -0
- package/dist/plugins/templates/shared/auth.test.js +116 -0
- package/dist/plugins/templates/shared/auth.test.js.map +1 -0
- package/dist/plugins/templates/shared/restapiintegration.d.ts +2 -0
- package/dist/plugins/templates/shared/restapiintegration.d.ts.map +1 -1
- package/dist/plugins/templates/shared/restapiintegration.js +3 -1
- package/dist/plugins/templates/shared/restapiintegration.js.map +1 -1
- package/dist/socket/dist-entry.test.d.ts +2 -0
- package/dist/socket/dist-entry.test.d.ts.map +1 -0
- package/dist/socket/dist-entry.test.js +34 -0
- package/dist/socket/dist-entry.test.js.map +1 -0
- package/dist/socket/heartbeat.d.ts +258 -0
- package/dist/socket/heartbeat.d.ts.map +1 -0
- package/dist/socket/heartbeat.js +307 -0
- package/dist/socket/heartbeat.js.map +1 -0
- package/dist/socket/heartbeat.test.d.ts +2 -0
- package/dist/socket/heartbeat.test.d.ts.map +1 -0
- package/dist/socket/heartbeat.test.js +431 -0
- package/dist/socket/heartbeat.test.js.map +1 -0
- package/dist/socket/index.d.ts +1 -0
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +1 -0
- package/dist/socket/index.js.map +1 -1
- package/dist/socket/util.d.ts.map +1 -1
- package/dist/socket/util.js +15 -1
- package/dist/socket/util.js.map +1 -1
- package/dist/socket/util.test.js +12 -2
- package/dist/socket/util.test.js.map +1 -1
- package/dist/types/ai/index.d.ts +3 -0
- package/dist/types/ai/index.d.ts.map +1 -1
- package/dist/types/ai/index.js +3 -0
- package/dist/types/ai/index.js.map +1 -1
- package/dist/types/application/index.d.ts +12 -0
- package/dist/types/application/index.d.ts.map +1 -1
- package/dist/types/application/index.js.map +1 -1
- package/dist/types/codeSecurity/index.d.ts +55 -1
- package/dist/types/codeSecurity/index.d.ts.map +1 -1
- package/dist/types/codeSecurity/index.js +21 -1
- package/dist/types/codeSecurity/index.js.map +1 -1
- package/dist/types/codeSecurity/index.test.d.ts +2 -0
- package/dist/types/codeSecurity/index.test.d.ts.map +1 -0
- package/dist/types/codeSecurity/index.test.js +19 -0
- package/dist/types/codeSecurity/index.test.js.map +1 -0
- package/dist/types/datasource/auth.d.ts +12 -1
- package/dist/types/datasource/auth.d.ts.map +1 -1
- package/dist/types/datasource/auth.js +20 -2
- package/dist/types/datasource/auth.js.map +1 -1
- package/dist/types/datasource/auth.test.js +3 -1
- package/dist/types/datasource/auth.test.js.map +1 -1
- package/dist/types/group/index.d.ts +1 -3
- package/dist/types/group/index.d.ts.map +1 -1
- package/dist/types/group/index.js +1 -3
- package/dist/types/group/index.js.map +1 -1
- package/dist/types/integration/index.d.ts +11 -1
- package/dist/types/integration/index.d.ts.map +1 -1
- package/dist/types/integration/index.js +11 -1
- package/dist/types/integration/index.js.map +1 -1
- package/dist/types/plugin/form.d.ts +32 -0
- package/dist/types/plugin/form.d.ts.map +1 -1
- package/dist/types/plugin/form.js +73 -1
- package/dist/types/plugin/form.js.map +1 -1
- package/dist/types/plugin/form.test.js +128 -0
- package/dist/types/plugin/form.test.js.map +1 -1
- package/dist/types/profile/index.d.ts +16 -1
- package/dist/types/profile/index.d.ts.map +1 -1
- package/dist/types/profile/index.js +7 -1
- package/dist/types/profile/index.js.map +1 -1
- package/dist/types/rbac/index.d.ts +2 -0
- package/dist/types/rbac/index.d.ts.map +1 -1
- package/dist/types/rbac/index.js +2 -0
- package/dist/types/rbac/index.js.map +1 -1
- package/dist/types/response/GetRecentApplicationsResponseBody.d.ts +4 -0
- package/dist/types/response/GetRecentApplicationsResponseBody.d.ts.map +1 -0
- package/dist/types/response/GetRecentApplicationsResponseBody.js +3 -0
- package/dist/types/response/GetRecentApplicationsResponseBody.js.map +1 -0
- package/dist/types/response/index.d.ts +1 -0
- package/dist/types/response/index.d.ts.map +1 -1
- package/dist/types/response/index.js +1 -0
- package/dist/types/response/index.js.map +1 -1
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.d.ts +49 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.d.ts.map +1 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.js +28 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.js.map +1 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.test.d.ts +2 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.test.d.ts.map +1 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.test.js +45 -0
- package/dist-esm/database-lifecycle/appDatabaseCompatibility.test.js.map +1 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.d.ts +12 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.d.ts.map +1 -1
- package/dist-esm/database-lifecycle/destructiveMigrations.js +113 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.js.map +1 -1
- package/dist-esm/database-lifecycle/destructiveMigrations.test.js +80 -1
- package/dist-esm/database-lifecycle/destructiveMigrations.test.js.map +1 -1
- package/dist-esm/database-lifecycle/index.d.ts +46 -2
- package/dist-esm/database-lifecycle/index.d.ts.map +1 -1
- package/dist-esm/database-lifecycle/index.js +123 -1
- package/dist-esm/database-lifecycle/index.js.map +1 -1
- package/dist-esm/database-lifecycle/providerDiagnostics.test.d.ts +2 -0
- package/dist-esm/database-lifecycle/providerDiagnostics.test.d.ts.map +1 -0
- package/dist-esm/database-lifecycle/providerDiagnostics.test.js +117 -0
- package/dist-esm/database-lifecycle/providerDiagnostics.test.js.map +1 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.d.ts +65 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.d.ts.map +1 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.js +79 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.js.map +1 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.test.d.ts +2 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.test.d.ts.map +1 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.test.js +283 -0
- package/dist-esm/environment-compatibility/appEnvironmentCompatibility.test.js.map +1 -0
- package/dist-esm/errors/http.d.ts +15 -4
- package/dist-esm/errors/http.d.ts.map +1 -1
- package/dist-esm/errors/http.js +22 -6
- package/dist-esm/errors/http.js.map +1 -1
- package/dist-esm/errors/http.test.d.ts +2 -0
- package/dist-esm/errors/http.test.d.ts.map +1 -0
- package/dist-esm/errors/http.test.js +26 -0
- package/dist-esm/errors/http.test.js.map +1 -0
- package/dist-esm/index.d.ts +2 -0
- package/dist-esm/index.d.ts.map +1 -1
- package/dist-esm/index.js +2 -0
- package/dist-esm/index.js.map +1 -1
- package/dist-esm/plugins/templates/restApiIntegration.d.ts.map +1 -1
- package/dist-esm/plugins/templates/restApiIntegration.js +2 -0
- package/dist-esm/plugins/templates/restApiIntegration.js.map +1 -1
- package/dist-esm/plugins/templates/shared/auth.d.ts +3 -1
- package/dist-esm/plugins/templates/shared/auth.d.ts.map +1 -1
- package/dist-esm/plugins/templates/shared/auth.js +129 -17
- package/dist-esm/plugins/templates/shared/auth.js.map +1 -1
- package/dist-esm/plugins/templates/shared/auth.test.d.ts +2 -0
- package/dist-esm/plugins/templates/shared/auth.test.d.ts.map +1 -0
- package/dist-esm/plugins/templates/shared/auth.test.js +114 -0
- package/dist-esm/plugins/templates/shared/auth.test.js.map +1 -0
- package/dist-esm/plugins/templates/shared/restapiintegration.d.ts +2 -0
- package/dist-esm/plugins/templates/shared/restapiintegration.d.ts.map +1 -1
- package/dist-esm/plugins/templates/shared/restapiintegration.js +3 -1
- package/dist-esm/plugins/templates/shared/restapiintegration.js.map +1 -1
- package/dist-esm/socket/dist-entry.test.d.ts +2 -0
- package/dist-esm/socket/dist-entry.test.d.ts.map +1 -0
- package/dist-esm/socket/dist-entry.test.js +29 -0
- package/dist-esm/socket/dist-entry.test.js.map +1 -0
- package/dist-esm/socket/heartbeat.d.ts +258 -0
- package/dist-esm/socket/heartbeat.d.ts.map +1 -0
- package/dist-esm/socket/heartbeat.js +303 -0
- package/dist-esm/socket/heartbeat.js.map +1 -0
- package/dist-esm/socket/heartbeat.test.d.ts +2 -0
- package/dist-esm/socket/heartbeat.test.d.ts.map +1 -0
- package/dist-esm/socket/heartbeat.test.js +429 -0
- package/dist-esm/socket/heartbeat.test.js.map +1 -0
- package/dist-esm/socket/index.d.ts +1 -0
- package/dist-esm/socket/index.d.ts.map +1 -1
- package/dist-esm/socket/index.js +1 -0
- package/dist-esm/socket/index.js.map +1 -1
- package/dist-esm/socket/util.d.ts.map +1 -1
- package/dist-esm/socket/util.js +15 -1
- package/dist-esm/socket/util.js.map +1 -1
- package/dist-esm/socket/util.test.js +12 -2
- package/dist-esm/socket/util.test.js.map +1 -1
- package/dist-esm/types/ai/index.d.ts +3 -0
- package/dist-esm/types/ai/index.d.ts.map +1 -1
- package/dist-esm/types/ai/index.js +3 -0
- package/dist-esm/types/ai/index.js.map +1 -1
- package/dist-esm/types/application/index.d.ts +12 -0
- package/dist-esm/types/application/index.d.ts.map +1 -1
- package/dist-esm/types/application/index.js.map +1 -1
- package/dist-esm/types/codeSecurity/index.d.ts +55 -1
- package/dist-esm/types/codeSecurity/index.d.ts.map +1 -1
- package/dist-esm/types/codeSecurity/index.js +17 -1
- package/dist-esm/types/codeSecurity/index.js.map +1 -1
- package/dist-esm/types/codeSecurity/index.test.d.ts +2 -0
- package/dist-esm/types/codeSecurity/index.test.d.ts.map +1 -0
- package/dist-esm/types/codeSecurity/index.test.js +17 -0
- package/dist-esm/types/codeSecurity/index.test.js.map +1 -0
- package/dist-esm/types/datasource/auth.d.ts +12 -1
- package/dist-esm/types/datasource/auth.d.ts.map +1 -1
- package/dist-esm/types/datasource/auth.js +19 -2
- package/dist-esm/types/datasource/auth.js.map +1 -1
- package/dist-esm/types/datasource/auth.test.js +3 -1
- package/dist-esm/types/datasource/auth.test.js.map +1 -1
- package/dist-esm/types/group/index.d.ts +1 -3
- package/dist-esm/types/group/index.d.ts.map +1 -1
- package/dist-esm/types/group/index.js +1 -3
- package/dist-esm/types/group/index.js.map +1 -1
- package/dist-esm/types/integration/index.d.ts +11 -1
- package/dist-esm/types/integration/index.d.ts.map +1 -1
- package/dist-esm/types/integration/index.js +11 -1
- package/dist-esm/types/integration/index.js.map +1 -1
- package/dist-esm/types/plugin/form.d.ts +32 -0
- package/dist-esm/types/plugin/form.d.ts.map +1 -1
- package/dist-esm/types/plugin/form.js +68 -0
- package/dist-esm/types/plugin/form.js.map +1 -1
- package/dist-esm/types/plugin/form.test.js +129 -1
- package/dist-esm/types/plugin/form.test.js.map +1 -1
- package/dist-esm/types/profile/index.d.ts +16 -1
- package/dist-esm/types/profile/index.d.ts.map +1 -1
- package/dist-esm/types/profile/index.js +7 -1
- package/dist-esm/types/profile/index.js.map +1 -1
- package/dist-esm/types/rbac/index.d.ts +2 -0
- package/dist-esm/types/rbac/index.d.ts.map +1 -1
- package/dist-esm/types/rbac/index.js +2 -0
- package/dist-esm/types/rbac/index.js.map +1 -1
- package/dist-esm/types/response/GetRecentApplicationsResponseBody.d.ts +4 -0
- package/dist-esm/types/response/GetRecentApplicationsResponseBody.d.ts.map +1 -0
- package/dist-esm/types/response/GetRecentApplicationsResponseBody.js +2 -0
- package/dist-esm/types/response/GetRecentApplicationsResponseBody.js.map +1 -0
- package/dist-esm/types/response/index.d.ts +1 -0
- package/dist-esm/types/response/index.d.ts.map +1 -1
- package/dist-esm/types/response/index.js +1 -0
- package/dist-esm/types/response/index.js.map +1 -1
- package/package.json +1 -1
- package/src/database-lifecycle/appDatabaseCompatibility.test.ts +55 -0
- package/src/database-lifecycle/appDatabaseCompatibility.ts +62 -0
- package/src/database-lifecycle/destructiveMigrations.test.ts +108 -1
- package/src/database-lifecycle/destructiveMigrations.ts +129 -0
- package/src/database-lifecycle/index.ts +173 -0
- package/src/database-lifecycle/providerDiagnostics.test.ts +134 -0
- package/src/environment-compatibility/appEnvironmentCompatibility.test.ts +326 -0
- package/src/environment-compatibility/appEnvironmentCompatibility.ts +173 -0
- package/src/errors/http.test.ts +32 -0
- package/src/errors/http.ts +24 -6
- package/src/index.ts +2 -0
- package/src/plugins/templates/restApiIntegration.ts +2 -0
- package/src/plugins/templates/shared/auth.test.ts +162 -0
- package/src/plugins/templates/shared/auth.ts +135 -18
- package/src/plugins/templates/shared/restapiintegration.ts +3 -1
- package/src/socket/dist-entry.test.ts +29 -0
- package/src/socket/heartbeat.test.ts +538 -0
- package/src/socket/heartbeat.ts +469 -0
- package/src/socket/index.ts +1 -0
- package/src/socket/util.test.ts +14 -2
- package/src/socket/util.ts +15 -1
- package/src/types/ai/index.ts +3 -0
- package/src/types/application/index.ts +14 -0
- package/src/types/codeSecurity/index.test.ts +21 -0
- package/src/types/codeSecurity/index.ts +83 -1
- package/src/types/datasource/auth.test.ts +3 -1
- package/src/types/datasource/auth.ts +24 -3
- package/src/types/group/index.ts +1 -3
- package/src/types/integration/index.ts +14 -0
- package/src/types/plugin/form.test.ts +174 -1
- package/src/types/plugin/form.ts +100 -2
- package/src/types/profile/index.ts +19 -1
- package/src/types/rbac/index.ts +2 -0
- package/src/types/response/GetRecentApplicationsResponseBody.ts +4 -0
- package/src/types/response/index.ts +1 -0
|
@@ -41,6 +41,7 @@ export * from './GetPublicApiResponseBody.js';
|
|
|
41
41
|
export * from './GetPublicOrganizationSummaryResponseBody.js';
|
|
42
42
|
export * from './IssueSuperblocksResponseBody.js';
|
|
43
43
|
export * from './GetAllApplicationsResponseBody.js';
|
|
44
|
+
export * from './GetRecentApplicationsResponseBody.js';
|
|
44
45
|
export * from './PatchApplicationResponseBody.js';
|
|
45
46
|
export * from './PatchHomePageItemsResponseBody.js';
|
|
46
47
|
export * from './ListApplicationBuildsResponseBody.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/response/index.ts"],"names":[],"mappings":"AAAA,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,iCAAiC,CAAC;AAChD,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sCAAsC,CAAC;AACrD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,oDAAoD,CAAC;AACnE,cAAc,wCAAwC,CAAC;AACvD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,oCAAoC,CAAC;AACnD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/response/index.ts"],"names":[],"mappings":"AAAA,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,iCAAiC,CAAC;AAChD,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sCAAsC,CAAC;AACrD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,oDAAoD,CAAC;AACnE,cAAc,wCAAwC,CAAC;AACvD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,oCAAoC,CAAC;AACnD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC;AACvD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC"}
|
|
@@ -41,6 +41,7 @@ export * from './GetPublicApiResponseBody.js';
|
|
|
41
41
|
export * from './GetPublicOrganizationSummaryResponseBody.js';
|
|
42
42
|
export * from './IssueSuperblocksResponseBody.js';
|
|
43
43
|
export * from './GetAllApplicationsResponseBody.js';
|
|
44
|
+
export * from './GetRecentApplicationsResponseBody.js';
|
|
44
45
|
export * from './PatchApplicationResponseBody.js';
|
|
45
46
|
export * from './PatchHomePageItemsResponseBody.js';
|
|
46
47
|
export * from './ListApplicationBuildsResponseBody.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/response/index.ts"],"names":[],"mappings":"AAAA,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,iCAAiC,CAAC;AAChD,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sCAAsC,CAAC;AACrD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,oDAAoD,CAAC;AACnE,cAAc,wCAAwC,CAAC;AACvD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,oCAAoC,CAAC;AACnD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/response/index.ts"],"names":[],"mappings":"AAAA,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,iCAAiC,CAAC;AAChD,cAAc,oCAAoC,CAAC;AACnD,cAAc,0CAA0C,CAAC;AACzD,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sCAAsC,CAAC;AACrD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,oDAAoD,CAAC;AACnE,cAAc,wCAAwC,CAAC;AACvD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,oCAAoC,CAAC;AACnD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC;AACvD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { ViewMode } from '../types/event/index.js';
|
|
4
|
+
import { type AppDatabaseTagCompatibility, rollUpAppDatabaseCompatibility } from './appDatabaseCompatibility.js';
|
|
5
|
+
|
|
6
|
+
function tag(overrides: Partial<AppDatabaseTagCompatibility> & Pick<AppDatabaseTagCompatibility, 'profileKey' | 'supportState'>) {
|
|
7
|
+
return {
|
|
8
|
+
availableModes: [ViewMode.EDITOR],
|
|
9
|
+
missingOperations: [],
|
|
10
|
+
requiredOperations: ['ensure_database', 'migrate_schema'],
|
|
11
|
+
...overrides
|
|
12
|
+
} satisfies AppDatabaseTagCompatibility;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('rolling up per-tag support into an app-wide verdict', () => {
|
|
16
|
+
test('an app whose every data tag is served is compatible', () => {
|
|
17
|
+
const rollUp = rollUpAppDatabaseCompatibility([
|
|
18
|
+
tag({ profileKey: 'staging', supportState: 'supported' }),
|
|
19
|
+
tag({ profileKey: 'production', supportState: 'supported' })
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
expect(rollUp).toEqual({ needsAttention: false, overallState: 'compatible' });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('one unserved data tag makes the whole app incompatible even when siblings are served', () => {
|
|
26
|
+
const rollUp = rollUpAppDatabaseCompatibility([
|
|
27
|
+
tag({ profileKey: 'staging', supportState: 'supported' }),
|
|
28
|
+
tag({ missingOperations: ['ensure_database'], profileKey: 'restricted', supportState: 'unsupported' })
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
expect(rollUp).toEqual({ needsAttention: true, overallState: 'incompatible' });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('a capability lookup outage is reported as temporary rather than as a missing capability', () => {
|
|
35
|
+
const rollUp = rollUpAppDatabaseCompatibility([
|
|
36
|
+
tag({ profileKey: 'staging', supportState: 'temporarily_unavailable' }),
|
|
37
|
+
tag({ profileKey: 'production', supportState: 'temporarily_unavailable' })
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
expect(rollUp).toEqual({ needsAttention: false, overallState: 'temporarily_unavailable' });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('a permanently unserved tag is still reported while another tag is only temporarily unknown', () => {
|
|
44
|
+
const rollUp = rollUpAppDatabaseCompatibility([
|
|
45
|
+
tag({ profileKey: 'staging', supportState: 'temporarily_unavailable' }),
|
|
46
|
+
tag({ missingOperations: ['migrate_schema'], profileKey: 'restricted', supportState: 'unsupported' })
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
expect(rollUp).toEqual({ needsAttention: true, overallState: 'incompatible' });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('an app with no data tags to check is compatible', () => {
|
|
53
|
+
expect(rollUpAppDatabaseCompatibility([])).toEqual({ needsAttention: false, overallState: 'compatible' });
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ViewMode } from '../types/event/index.js';
|
|
2
|
+
import type { LifecycleOperation } from './index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Whether lifecycle workers can serve App Database work for one data tag.
|
|
6
|
+
*
|
|
7
|
+
* `unsupported` is a standing gap: workers are connected, but none of them
|
|
8
|
+
* handles this tag. `temporarily_unavailable` means we could not tell —
|
|
9
|
+
* nothing is registered right now, or the lookup itself failed — so the tag
|
|
10
|
+
* may start working again without anyone changing the app.
|
|
11
|
+
*/
|
|
12
|
+
export const APP_DATABASE_TAG_SUPPORT_STATES = ['supported', 'temporarily_unavailable', 'unsupported'] as const;
|
|
13
|
+
export type AppDatabaseTagSupportState = (typeof APP_DATABASE_TAG_SUPPORT_STATES)[number];
|
|
14
|
+
|
|
15
|
+
export const APP_DATABASE_COMPATIBILITY_STATES = ['compatible', 'incompatible', 'temporarily_unavailable'] as const;
|
|
16
|
+
export type AppDatabaseCompatibilityState = (typeof APP_DATABASE_COMPATIBILITY_STATES)[number];
|
|
17
|
+
|
|
18
|
+
/** Lifecycle operations an App Database cannot work without. */
|
|
19
|
+
export const APP_DATABASE_REQUIRED_OPERATIONS: readonly LifecycleOperation[] = ['ensure_database', 'migrate_schema'];
|
|
20
|
+
|
|
21
|
+
export type AppDatabaseTagCompatibility = {
|
|
22
|
+
/** App view modes that offer this data tag, for messaging. */
|
|
23
|
+
availableModes: ViewMode[];
|
|
24
|
+
missingOperations: LifecycleOperation[];
|
|
25
|
+
profileKey: string;
|
|
26
|
+
requiredOperations: LifecycleOperation[];
|
|
27
|
+
supportState: AppDatabaseTagSupportState;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type AppDatabaseCompatibility = {
|
|
31
|
+
applicationId: string;
|
|
32
|
+
/**
|
|
33
|
+
* Whether the app declares an App Database right now. An app without one is
|
|
34
|
+
* never blocked by a data tag gap, so callers use this to stay quiet instead
|
|
35
|
+
* of warning about a problem the user does not have.
|
|
36
|
+
*/
|
|
37
|
+
hasAppDatabase: boolean;
|
|
38
|
+
/** True only when someone has to change the app for it to work again. */
|
|
39
|
+
needsAttention: boolean;
|
|
40
|
+
overallState: AppDatabaseCompatibilityState;
|
|
41
|
+
/** Every data tag the app can run App Database work for, sorted by key. */
|
|
42
|
+
tags: AppDatabaseTagCompatibility[];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Fold per-tag support into the app-wide verdict. A standing gap outranks a
|
|
47
|
+
* temporary one: a tag no worker serves has to be reported even while another
|
|
48
|
+
* tag's capability is momentarily unknown, otherwise the outage hides work the
|
|
49
|
+
* user actually has to do.
|
|
50
|
+
*/
|
|
51
|
+
export function rollUpAppDatabaseCompatibility(tags: readonly AppDatabaseTagCompatibility[]): {
|
|
52
|
+
needsAttention: boolean;
|
|
53
|
+
overallState: AppDatabaseCompatibilityState;
|
|
54
|
+
} {
|
|
55
|
+
if (tags.some((tag) => tag.supportState === 'unsupported')) {
|
|
56
|
+
return { needsAttention: true, overallState: 'incompatible' };
|
|
57
|
+
}
|
|
58
|
+
if (tags.some((tag) => tag.supportState === 'temporarily_unavailable')) {
|
|
59
|
+
return { needsAttention: false, overallState: 'temporarily_unavailable' };
|
|
60
|
+
}
|
|
61
|
+
return { needsAttention: false, overallState: 'compatible' };
|
|
62
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import { analyzeDestructiveMigrations } from './destructiveMigrations.js';
|
|
3
|
+
import { analyzeDestructiveMigrations, analyzeDestructiveMigrationsRequiringAck } from './destructiveMigrations.js';
|
|
4
4
|
|
|
5
5
|
describe('analyzeDestructiveMigrations', () => {
|
|
6
6
|
test('returns empty when SQL has no destructive statements', () => {
|
|
@@ -114,3 +114,110 @@ CREATE TABLE users (id int);
|
|
|
114
114
|
expect(findings[1]).toMatchObject({ fileName: 'b.sql', kind: 'truncate' });
|
|
115
115
|
});
|
|
116
116
|
});
|
|
117
|
+
|
|
118
|
+
describe('analyzeDestructiveMigrationsRequiringAck', () => {
|
|
119
|
+
test('does not require an ack for a drop of a table created earlier in the same batch', () => {
|
|
120
|
+
// The whole set runs as one batch. Dropping a table that this batch just
|
|
121
|
+
// created removes nothing that existed before the batch started.
|
|
122
|
+
expect(
|
|
123
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
124
|
+
{ fileName: '0001_init.sql', sql: 'CREATE TABLE users (id int);' },
|
|
125
|
+
{ fileName: '0002_drop.sql', sql: 'DROP TABLE users;' }
|
|
126
|
+
])
|
|
127
|
+
).toEqual([]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('still requires an ack for a drop of a table the batch never created', () => {
|
|
131
|
+
// A ready database can hold tables written by the app with no migrate
|
|
132
|
+
// history. A DROP of those is genuinely destructive.
|
|
133
|
+
expect(analyzeDestructiveMigrationsRequiringAck([{ fileName: '0001_drop.sql', sql: 'DROP TABLE orders;' }])).toEqual([
|
|
134
|
+
expect.objectContaining({ fileName: '0001_drop.sql', kind: 'drop_table' })
|
|
135
|
+
]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('still requires an ack when the drop appears before the create in the batch', () => {
|
|
139
|
+
// DROP then CREATE would wipe any pre-existing table of that name.
|
|
140
|
+
expect(
|
|
141
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
142
|
+
{ fileName: '0001_drop.sql', sql: 'DROP TABLE users;' },
|
|
143
|
+
{ fileName: '0002_init.sql', sql: 'CREATE TABLE users (id int);' }
|
|
144
|
+
])
|
|
145
|
+
).toEqual([expect.objectContaining({ kind: 'drop_table' })]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('does not require an ack for truncate or drop column on a table created earlier in the batch', () => {
|
|
149
|
+
expect(
|
|
150
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
151
|
+
{
|
|
152
|
+
fileName: '0001_init.sql',
|
|
153
|
+
sql: 'CREATE TABLE users (id int, email text); ALTER TABLE users ADD COLUMN name text;'
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
fileName: '0002_cleanup.sql',
|
|
157
|
+
sql: 'TRUNCATE TABLE users; ALTER TABLE users DROP COLUMN email;'
|
|
158
|
+
}
|
|
159
|
+
])
|
|
160
|
+
).toEqual([]);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('still requires an ack for drop database and drop schema even after creates in the batch', () => {
|
|
164
|
+
expect(
|
|
165
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
166
|
+
{ fileName: '0001.sql', sql: 'CREATE SCHEMA app; CREATE DATABASE scratch;' },
|
|
167
|
+
{ fileName: '0002.sql', sql: 'DROP SCHEMA app; DROP DATABASE scratch;' }
|
|
168
|
+
])
|
|
169
|
+
.map((finding) => finding.kind)
|
|
170
|
+
.sort()
|
|
171
|
+
).toEqual(['drop_database', 'drop_schema']);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('still requires an ack for a multi-table drop when any target was not created in the batch', () => {
|
|
175
|
+
// DROP TABLE can list several names. Covering only the first must not
|
|
176
|
+
// suppress the statement — the other names may already hold customer data.
|
|
177
|
+
expect(
|
|
178
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
179
|
+
{ fileName: '0001_init.sql', sql: 'CREATE TABLE users (id int);' },
|
|
180
|
+
{ fileName: '0002_drop.sql', sql: 'DROP TABLE IF EXISTS users, orders;' }
|
|
181
|
+
])
|
|
182
|
+
).toEqual([expect.objectContaining({ kind: 'drop_table' })]);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('still requires an ack for a multi-table truncate when any target was not created in the batch', () => {
|
|
186
|
+
expect(
|
|
187
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
188
|
+
{ fileName: '0001_init.sql', sql: 'CREATE TABLE users (id int);' },
|
|
189
|
+
{ fileName: '0002_cleanup.sql', sql: 'TRUNCATE TABLE users, orders;' }
|
|
190
|
+
])
|
|
191
|
+
).toEqual([expect.objectContaining({ kind: 'truncate' })]);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('does not require an ack for a multi-table drop when every target was created in the batch', () => {
|
|
195
|
+
expect(
|
|
196
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
197
|
+
{ fileName: '0001_init.sql', sql: 'CREATE TABLE users (id int); CREATE TABLE orders (id int);' },
|
|
198
|
+
{ fileName: '0002_drop.sql', sql: 'DROP TABLE users, orders;' }
|
|
199
|
+
])
|
|
200
|
+
).toEqual([]);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('still requires an ack when create and drop use different schema qualification', () => {
|
|
204
|
+
// Exact identifier match only. public.users and users may be the same
|
|
205
|
+
// relation in Postgres, but we cannot prove that from the SQL text alone,
|
|
206
|
+
// so mismatched spelling stays acknowledged (fail closed).
|
|
207
|
+
expect(
|
|
208
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
209
|
+
{ fileName: '0001_init.sql', sql: 'CREATE TABLE users (id int);' },
|
|
210
|
+
{ fileName: '0002_drop.sql', sql: 'DROP TABLE public.users;' }
|
|
211
|
+
])
|
|
212
|
+
).toEqual([expect.objectContaining({ kind: 'drop_table' })]);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test('does not require an ack when create and drop use the same schema-qualified name', () => {
|
|
216
|
+
expect(
|
|
217
|
+
analyzeDestructiveMigrationsRequiringAck([
|
|
218
|
+
{ fileName: '0001_init.sql', sql: 'CREATE TABLE public.users (id int);' },
|
|
219
|
+
{ fileName: '0002_drop.sql', sql: 'DROP TABLE public.users;' }
|
|
220
|
+
])
|
|
221
|
+
).toEqual([]);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
@@ -81,6 +81,99 @@ function classifyStatement(statement: string): DestructiveMigrationKind | undefi
|
|
|
81
81
|
return undefined;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
function normalizeSqlIdent(raw: string): string {
|
|
85
|
+
return raw.replace(/"/g, '').toLowerCase();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Optional schema-qualified identifier, with optional quoting on each part. */
|
|
89
|
+
const SQL_IDENT = String.raw`(?:"[^"]+"|\w+)(?:\.(?:"[^"]+"|\w+))?`;
|
|
90
|
+
|
|
91
|
+
function matchFirstIdent(statement: string, pattern: RegExp): string | undefined {
|
|
92
|
+
const match = pattern.exec(statement);
|
|
93
|
+
const raw = match?.[1];
|
|
94
|
+
return raw === undefined ? undefined : normalizeSqlIdent(raw);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Pull every table name from a comma-separated DROP TABLE / TRUNCATE list.
|
|
99
|
+
* Returns undefined when the list cannot be parsed safely — callers must then
|
|
100
|
+
* require acknowledgment (fail closed).
|
|
101
|
+
*/
|
|
102
|
+
function matchTableListTargets(statement: string, header: RegExp): string[] | undefined {
|
|
103
|
+
const headerMatch = header.exec(statement);
|
|
104
|
+
if (headerMatch === null) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const afterHeader = statement.slice(headerMatch[0].length);
|
|
108
|
+
const listPart = afterHeader.split(/\b(?:CASCADE|RESTRICT|CONTINUE\s+IDENTITY|RESTART\s+IDENTITY)\b/i)[0] ?? '';
|
|
109
|
+
const tables: string[] = [];
|
|
110
|
+
for (const part of listPart.split(',')) {
|
|
111
|
+
const trimmed = part.trim();
|
|
112
|
+
if (trimmed.length === 0) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// TRUNCATE allows ONLY before each name.
|
|
116
|
+
const raw = matchFirstIdent(trimmed, new RegExp(String.raw`^(?:ONLY\s+)?(${SQL_IDENT})`, 'i'));
|
|
117
|
+
if (raw === undefined) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
tables.push(raw);
|
|
121
|
+
}
|
|
122
|
+
return tables.length > 0 ? tables : undefined;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function allTablesCreatedInBatch(tables: string[] | undefined, createdTables: Set<string>): boolean {
|
|
126
|
+
return tables !== undefined && tables.length > 0 && tables.every((table) => createdTables.has(table));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function recordCreates(statement: string, createdTables: Set<string>, createdColumns: Set<string>): void {
|
|
130
|
+
const table = matchFirstIdent(statement, new RegExp(String.raw`^\s*CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(${SQL_IDENT})`, 'i'));
|
|
131
|
+
if (table !== undefined) {
|
|
132
|
+
createdTables.add(table);
|
|
133
|
+
}
|
|
134
|
+
const addColumn = new RegExp(String.raw`^\s*ALTER\s+TABLE\s+(${SQL_IDENT})\s+ADD\s+(?:COLUMN\s+)?(${SQL_IDENT})`, 'i').exec(statement);
|
|
135
|
+
if (addColumn?.[1] !== undefined && addColumn[2] !== undefined) {
|
|
136
|
+
createdColumns.add(`${normalizeSqlIdent(addColumn[1])}.${normalizeSqlIdent(addColumn[2])}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function isCoveredByEarlierCreate(
|
|
141
|
+
kind: DestructiveMigrationKind,
|
|
142
|
+
statement: string,
|
|
143
|
+
createdTables: Set<string>,
|
|
144
|
+
createdColumns: Set<string>
|
|
145
|
+
): boolean {
|
|
146
|
+
switch (kind) {
|
|
147
|
+
case 'drop_table': {
|
|
148
|
+
return allTablesCreatedInBatch(matchTableListTargets(statement, /^\s*DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?/i), createdTables);
|
|
149
|
+
}
|
|
150
|
+
case 'truncate': {
|
|
151
|
+
return allTablesCreatedInBatch(matchTableListTargets(statement, /^\s*TRUNCATE\s+(?:TABLE\s+)?/i), createdTables);
|
|
152
|
+
}
|
|
153
|
+
case 'drop_column': {
|
|
154
|
+
const alterDrop = new RegExp(
|
|
155
|
+
String.raw`^\s*ALTER\s+TABLE\s+(${SQL_IDENT})\s+[\s\S]*?\bDROP\s+(?:COLUMN\s+)?(?!CONSTRAINT\b|INDEX\b|TRIGGER\b|RULE\b|POLICY\b|STATISTICS\b|IDENTITY\b|NOT\b|DEFAULT\b|EXPRESSION\b)(${SQL_IDENT})`,
|
|
156
|
+
'i'
|
|
157
|
+
).exec(statement);
|
|
158
|
+
if (alterDrop?.[1] !== undefined && alterDrop[2] !== undefined) {
|
|
159
|
+
const table = normalizeSqlIdent(alterDrop[1]);
|
|
160
|
+
const column = normalizeSqlIdent(alterDrop[2]);
|
|
161
|
+
return createdTables.has(table) || createdColumns.has(`${table}.${column}`);
|
|
162
|
+
}
|
|
163
|
+
// Standalone DROP COLUMN has no table context — cannot prove coverage.
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
case 'drop_database':
|
|
167
|
+
case 'drop_schema':
|
|
168
|
+
// Creating the container in the same batch does not prove it is free of
|
|
169
|
+
// customer data, so these always require an acknowledgment.
|
|
170
|
+
return false;
|
|
171
|
+
default: {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
84
177
|
/**
|
|
85
178
|
* Scans migration SQL for schema-destroying statements that require an
|
|
86
179
|
* explicit user acknowledgment before apply/deploy.
|
|
@@ -103,3 +196,39 @@ export function analyzeDestructiveMigrations(files: DestructiveMigrationFile[]):
|
|
|
103
196
|
}
|
|
104
197
|
return findings;
|
|
105
198
|
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Like analyzeDestructiveMigrations, but omits drops/truncates of objects this
|
|
202
|
+
* same unscanned batch created earlier. Those remove nothing that existed before
|
|
203
|
+
* the batch started, so they are not acknowledged. A drop that appears before
|
|
204
|
+
* its create, or that targets an object the batch never creates, still requires
|
|
205
|
+
* an ack — including when the control plane has never migrated this binding,
|
|
206
|
+
* because a ready database can hold tables the app wrote without migrations.
|
|
207
|
+
*
|
|
208
|
+
* DROP DATABASE / DROP SCHEMA are never suppressed this way: creating the
|
|
209
|
+
* container in the same batch does not prove it is free of customer data.
|
|
210
|
+
*/
|
|
211
|
+
export function analyzeDestructiveMigrationsRequiringAck(files: DestructiveMigrationFile[]): DestructiveMigrationFinding[] {
|
|
212
|
+
const createdTables = new Set<string>();
|
|
213
|
+
const createdColumns = new Set<string>();
|
|
214
|
+
const findings: DestructiveMigrationFinding[] = [];
|
|
215
|
+
for (const file of files) {
|
|
216
|
+
const statements = splitStatements(stripSqlComments(file.sql));
|
|
217
|
+
for (const statement of statements) {
|
|
218
|
+
recordCreates(statement, createdTables, createdColumns);
|
|
219
|
+
const kind = classifyStatement(statement);
|
|
220
|
+
if (kind === undefined) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (isCoveredByEarlierCreate(kind, statement, createdTables, createdColumns)) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
findings.push({
|
|
227
|
+
fileName: file.fileName,
|
|
228
|
+
kind,
|
|
229
|
+
excerpt: excerptFor(statement)
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return findings;
|
|
234
|
+
}
|
|
@@ -78,6 +78,7 @@ export const LIFECYCLE_ERROR_CODES = [
|
|
|
78
78
|
'terraform_failed',
|
|
79
79
|
'migration_failed',
|
|
80
80
|
'callback_failed',
|
|
81
|
+
'configuration_conflict',
|
|
81
82
|
// Server-side classification for a terminal callback that arrived for a
|
|
82
83
|
// request whose desiredSpecHash no longer matches the binding (binding has
|
|
83
84
|
// moved to a newer spec). The callback's metadata/state is discarded and
|
|
@@ -87,6 +88,176 @@ export const LIFECYCLE_ERROR_CODES = [
|
|
|
87
88
|
|
|
88
89
|
export type LifecycleErrorCode = (typeof LIFECYCLE_ERROR_CODES)[number];
|
|
89
90
|
|
|
91
|
+
export const LIFECYCLE_PROVIDER_DIAGNOSTIC_PHASES = ['apply', 'destroy', 'init', 'plan', 'unknown'] as const;
|
|
92
|
+
export const MAX_LIFECYCLE_PROVIDER_DIAGNOSTICS = 3;
|
|
93
|
+
export const LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_SERVICE_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
|
|
94
|
+
export const LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_OPERATION_PATTERN = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
|
|
95
|
+
export const LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_ERROR_CODE_PATTERN = /^[A-Za-z][A-Za-z0-9.]{0,63}$/;
|
|
96
|
+
export const LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_REQUEST_ID_PATTERN =
|
|
97
|
+
/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/;
|
|
98
|
+
export const LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_S3_REQUEST_ID_PATTERN = /^[0-9A-Za-z]{16}$/;
|
|
99
|
+
export const LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_DYNAMODB_REQUEST_ID_PATTERN = /^[0-9A-Za-z]{52}$/;
|
|
100
|
+
export const LIFECYCLE_PROVIDER_DIAGNOSTIC_POSTGRESQL_SQL_STATE_PATTERN = /^[0-9A-Za-z]{5}$/;
|
|
101
|
+
|
|
102
|
+
export function isLifecycleProviderDiagnosticAwsRequestId(service: string, requestId: unknown): requestId is string {
|
|
103
|
+
if (typeof requestId !== 'string') {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_REQUEST_ID_PATTERN.test(requestId)) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (service === 's3') {
|
|
110
|
+
return LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_S3_REQUEST_ID_PATTERN.test(requestId);
|
|
111
|
+
}
|
|
112
|
+
if (service === 'dynamodb') {
|
|
113
|
+
return LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_DYNAMODB_REQUEST_ID_PATTERN.test(requestId);
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type LifecycleProviderDiagnosticPhase = (typeof LIFECYCLE_PROVIDER_DIAGNOSTIC_PHASES)[number];
|
|
119
|
+
|
|
120
|
+
type LifecycleProviderDiagnosticBase = {
|
|
121
|
+
phase: LifecycleProviderDiagnosticPhase;
|
|
122
|
+
retryable: boolean;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export type LifecycleAwsProviderDiagnostic = LifecycleProviderDiagnosticBase & {
|
|
126
|
+
provider: 'aws';
|
|
127
|
+
service: string;
|
|
128
|
+
operation: string;
|
|
129
|
+
errorCode: string;
|
|
130
|
+
requestId?: string;
|
|
131
|
+
nextAction: 'review_aws_operation';
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export type LifecyclePostgresqlProviderDiagnostic = LifecycleProviderDiagnosticBase & {
|
|
135
|
+
provider: 'postgresql';
|
|
136
|
+
sqlState: string;
|
|
137
|
+
nextAction: 'review_database_operation';
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Sanitized, allowlisted provider facts emitted by the lifecycle worker.
|
|
141
|
+
// Provider-authored summary/detail text is deliberately not part of this
|
|
142
|
+
// contract; consumers can display these fields without forwarding raw
|
|
143
|
+
// OpenTofu output.
|
|
144
|
+
export type LifecycleProviderDiagnostic = LifecycleAwsProviderDiagnostic | LifecyclePostgresqlProviderDiagnostic;
|
|
145
|
+
|
|
146
|
+
export type LifecycleProviderDiagnosticCandidateProvider = 'aws' | 'postgresql' | 'unknown';
|
|
147
|
+
|
|
148
|
+
export type LifecycleProviderDiagnosticCandidateInspection = {
|
|
149
|
+
provider: LifecycleProviderDiagnosticCandidateProvider;
|
|
150
|
+
diagnostic?: LifecycleProviderDiagnostic;
|
|
151
|
+
rejectedFields?: string[];
|
|
152
|
+
sanitizedFields?: string[];
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const lifecycleProviderDiagnosticPhases = new Set<string>(LIFECYCLE_PROVIDER_DIAGNOSTIC_PHASES);
|
|
156
|
+
|
|
157
|
+
function lifecycleProviderDiagnosticCandidateProvider(value: unknown): LifecycleProviderDiagnosticCandidateProvider {
|
|
158
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
159
|
+
return 'unknown';
|
|
160
|
+
}
|
|
161
|
+
const provider = (value as Record<string, unknown>).provider;
|
|
162
|
+
return provider === 'aws' || provider === 'postgresql' ? provider : 'unknown';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function lifecycleProviderDiagnosticPhase(value: unknown): LifecycleProviderDiagnosticPhase {
|
|
166
|
+
return typeof value === 'string' && lifecycleProviderDiagnosticPhases.has(value)
|
|
167
|
+
? (value as LifecycleProviderDiagnosticPhase)
|
|
168
|
+
: 'unknown';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function invalidDiagnosticString(value: unknown, pattern: RegExp): boolean {
|
|
172
|
+
return typeof value !== 'string' || !pattern.test(value);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Canonical validation boundary for one provider diagnostic. The output is
|
|
177
|
+
* rebuilt from allowlisted facts, provider-authored text and unknown fields are
|
|
178
|
+
* discarded, and decorative fields such as nextAction are derived locally.
|
|
179
|
+
*/
|
|
180
|
+
export function inspectLifecycleProviderDiagnosticCandidate(value: unknown): LifecycleProviderDiagnosticCandidateInspection {
|
|
181
|
+
const provider = lifecycleProviderDiagnosticCandidateProvider(value);
|
|
182
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
183
|
+
return { provider, rejectedFields: ['(root)'] };
|
|
184
|
+
}
|
|
185
|
+
const candidate = value as Record<string, unknown>;
|
|
186
|
+
if (provider === 'unknown') {
|
|
187
|
+
return { provider, rejectedFields: ['provider'] };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (provider === 'aws') {
|
|
191
|
+
const rejectedFields: string[] = [];
|
|
192
|
+
if (invalidDiagnosticString(candidate.errorCode, LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_ERROR_CODE_PATTERN)) {
|
|
193
|
+
rejectedFields.push('errorCode');
|
|
194
|
+
}
|
|
195
|
+
if (invalidDiagnosticString(candidate.operation, LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_OPERATION_PATTERN)) {
|
|
196
|
+
rejectedFields.push('operation');
|
|
197
|
+
}
|
|
198
|
+
if (typeof candidate.retryable !== 'boolean') {
|
|
199
|
+
rejectedFields.push('retryable');
|
|
200
|
+
}
|
|
201
|
+
if (invalidDiagnosticString(candidate.service, LIFECYCLE_PROVIDER_DIAGNOSTIC_AWS_SERVICE_PATTERN)) {
|
|
202
|
+
rejectedFields.push('service');
|
|
203
|
+
}
|
|
204
|
+
if (rejectedFields.length > 0) {
|
|
205
|
+
return { provider, rejectedFields };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const requestId = candidate.requestId;
|
|
209
|
+
const hasSafeRequestId = isLifecycleProviderDiagnosticAwsRequestId(candidate.service as string, requestId);
|
|
210
|
+
return {
|
|
211
|
+
diagnostic: {
|
|
212
|
+
errorCode: candidate.errorCode as string,
|
|
213
|
+
nextAction: 'review_aws_operation',
|
|
214
|
+
operation: candidate.operation as string,
|
|
215
|
+
phase: lifecycleProviderDiagnosticPhase(candidate.phase),
|
|
216
|
+
provider,
|
|
217
|
+
...(hasSafeRequestId ? { requestId } : {}),
|
|
218
|
+
retryable: candidate.retryable as boolean,
|
|
219
|
+
service: candidate.service as string
|
|
220
|
+
},
|
|
221
|
+
provider,
|
|
222
|
+
...(requestId !== undefined && !hasSafeRequestId ? { sanitizedFields: ['requestId'] } : {})
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const rejectedFields: string[] = [];
|
|
227
|
+
if (typeof candidate.retryable !== 'boolean') {
|
|
228
|
+
rejectedFields.push('retryable');
|
|
229
|
+
}
|
|
230
|
+
if (invalidDiagnosticString(candidate.sqlState, LIFECYCLE_PROVIDER_DIAGNOSTIC_POSTGRESQL_SQL_STATE_PATTERN)) {
|
|
231
|
+
rejectedFields.push('sqlState');
|
|
232
|
+
}
|
|
233
|
+
if (rejectedFields.length > 0) {
|
|
234
|
+
return { provider, rejectedFields };
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
diagnostic: {
|
|
238
|
+
nextAction: 'review_database_operation',
|
|
239
|
+
phase: lifecycleProviderDiagnosticPhase(candidate.phase),
|
|
240
|
+
provider,
|
|
241
|
+
retryable: candidate.retryable as boolean,
|
|
242
|
+
sqlState: candidate.sqlState as string
|
|
243
|
+
},
|
|
244
|
+
provider
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function sanitizeLifecycleProviderDiagnostics(value: unknown): LifecycleProviderDiagnostic[] | undefined {
|
|
249
|
+
if (!Array.isArray(value)) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
const diagnostics = value
|
|
253
|
+
.flatMap((candidate) => {
|
|
254
|
+
const diagnostic = inspectLifecycleProviderDiagnosticCandidate(candidate).diagnostic;
|
|
255
|
+
return diagnostic ? [diagnostic] : [];
|
|
256
|
+
})
|
|
257
|
+
.slice(0, MAX_LIFECYCLE_PROVIDER_DIAGNOSTICS);
|
|
258
|
+
return diagnostics.length > 0 ? diagnostics : undefined;
|
|
259
|
+
}
|
|
260
|
+
|
|
90
261
|
export type PhysicalMasterCredentialRef = {
|
|
91
262
|
resolver: 'aws_secrets_manager';
|
|
92
263
|
ref: string;
|
|
@@ -201,6 +372,7 @@ export type LifecycleMigration = {
|
|
|
201
372
|
|
|
202
373
|
export {
|
|
203
374
|
analyzeDestructiveMigrations,
|
|
375
|
+
analyzeDestructiveMigrationsRequiringAck,
|
|
204
376
|
DESTRUCTIVE_MIGRATION_ACK_REQUIRED,
|
|
205
377
|
DESTRUCTIVE_MIGRATION_ACK_REQUIRED_MESSAGE,
|
|
206
378
|
DESTRUCTIVE_MIGRATION_SCAN_UNAVAILABLE
|
|
@@ -234,6 +406,7 @@ export type PhysicalPoolProvisioningActor = {
|
|
|
234
406
|
|
|
235
407
|
export type PhysicalPoolProvisioningError = {
|
|
236
408
|
code: string;
|
|
409
|
+
diagnostics?: LifecycleProviderDiagnostic[];
|
|
237
410
|
message: string;
|
|
238
411
|
};
|
|
239
412
|
|